자원 즉 사용자에게 제공할 데이터와 정보는 인터넷 어딘가에 존재하는 서버로 부터 받아와야한다. 만약 클라이언트 안에 모든 자원이 들어있다면 자원이 변경될 때마다 클라이언트를 새롭게 업데이트하여 배포해야하는 문제가 발생한다. 따라서 실시간으로 변하는 정보를 제공해야 하는 상황이 생기기 마련인데 이때 필요한 것이 서버이다. 서버(server)는 말 그대로 제공자의 역할을 하여 클라이언트에서 보내는 요청에 응답을 하는 역할을 한다.
이와 같이 소프트웨어 시스템을 클라이언트 계층과 서버 계층으로 2개로 나누어 관리하는 구조를 2티어 아키텍처
또는 클라이언트 - 서버
아키텍처 라고 부른다.
클라이언트가 서버에 요청을 하면 서버는 응답과 리소스를 제공한다.
일반적으로 서버는 리소스를 전달만하며 리소스를 저장하는 곳은 데이터베이스이다. 클라이언트 서버 데이터베이스로 구성되는 구조를 3티어 아키텍처라고 부른다.
이때 사용자의 접근과 가까운 클라이언트를 담당하는 직군을 프론트엔드, 사용자에게 제공하는 자원과 관련된 서버와 데이터베이스를 담당하는 직군을 벡엔드라고 한다.
우리가 가게에 들어가서 주문을 할때 외계어로 할 수 없듯이 클라이언트와 서버가 서로 통신을 주고 받기 위해서는 어느정도 정해진 규칙과 약속을 따라야 한다. 이 때 사용하는 용어가 프로토콜
인데 프로토콜
은 통신 규약, 즉 약속이다. 요청을 하기 위해 지켜야하는 약속들이 존재하며 클라이언트와 서버가 통신하기 위해 지켜야하는 통신 규약을 HTTP
라고 부른다. HTTP
는 HypterText Transfer Protocol
의 약자이다.
우리는 특정 주문을 하기위해 오프라인에서 점원을 통해, 앱을 이용하여 온라인을 통해 또는 키오스크를 통해서 주문하기도 한다. 이와 같은 모든 것들이 프로토콜이 된다. 각각의 주문은 정해진 규칙과 약속이 있으며 클라이언트는 이 규약을 따라 요청을 해야만 적절한 요청을 보낼 수 있다.
오프라인에서 점원을 통해 주문하는 프로토콜에 대해서 간단하게 적어보자.
3번에 주목해보자. 이때 제공 가능한 메뉴들을 클라이언트가 어떻게 알 수 있을까. 클라이언트는 서버의 내부구조를 모르기 때문에 어떤 요청을 보낼 수 있는지 알 수 없다. 우리가 가게에서 주문을 할 때는 메뉴판을 보고 주문을 하듯이 클라이언트가 서버에 요청을 보내기 위해 필요한 것이 바로 API 이다.
API (Application Programming Interface) 는 클라이언트가 서버에 요청을 보낼 수 있게 하기위해 만들어졌다. 여기서 인터페이스란 의사소통이 가능하도록 만들어진 접점을 의미한다.
서버는 리소스 전달을 위한 메뉴판, 즉 API 문서를 작성해야 클라이언트가 적절한 요청을 보낼 수 있으며 인터넷에 있는 데이터를 요청할 때 HTTP 를 사용하여 주소(url, uri)를 통해 접근한다.
주소뿐만 아니라 메소드를 사용하여 HTTP 요청을 보내며 메소드는 리소스와 관련된 행동을 지정한다. 이때 사용하는 메소드는 GET
(조회), POST
(추가), PUT
(갱신), PATCH
(갱신), DELETE
(삭제) 가 대표적이다.
클라이언트는 API 를 보는것만으로 어떤 요청이 가능할 지 예상할 수 있어야 한다. 만약 API 가 제멋대로 작성되어 있다면 클라이언트에서 일일이 API 를 사용해보며 시간을 소비하는 일이 발생할 수 있다. 때문에 API 의 사용목적을 클라이언트가 이해하기 쉽게 디자인 하는것이 중요하다.
API를 적절하게 디자인하기 위해서는 HTTP 메소드를 적절히 활용해야 한다. GET을 요청했는데 데이터가 사라져버린다면 API가 적절하게 디자인 됐다고 보기 어렵다. 메뉴판에 추가라고 된 카테고리에서 물을 선택해서 요청했는데 점원이 나타나서 마시던 물을 가져가는 느낌이 아닐까...
뿐만 아니라 Query string
, Path Variable
를 활용하여 API 의 URL 을 디자인 할 수 있다.
GET /users?age=20&weight=70
보통 Query string
은 GET 을 통해 조회를 할 때 특정 분류에 대해서 데이터를 불러오고 싶을 경우 사용한다. 위는 나이가 20 이면서 몸무가게 70 인 유저의 정보를 부르기 위해 디자인 된 API 의 URL 이다. ?
와 &
를 사용하여 Query string
을 작성할 수 있으며 이때 사용 된 age
와 weight
를 파라미터라고 한다.
DELETE /users/1
경로를 지정하여 특정 id 값을 가지는 데이터에 대한 요청을 보낼 수 있다. 위의 경우 1이라는 아이디값을 가지는 유저를 삭제해 달라는 요청을 보내는 API 로 예상 할 수 있다.
로이 필딩이 논문에서 제시한 REST 방법론을 보다 더 실용적으로 적용하기 위해 레오나르드 리차드슨은 REST API를 잘 적용하기 위한 4단계 모델을 만들었는데 REST 성숙도 모델
이라고 불리며 총 4단계로 나누어 진다.
앞서 이야기한 로이 필딩은 이 모델의 모든 단계를 충족해야 REST API라고 부를 수 있다고 주장했지만 실제로 엄밀하게 3단계까지 지키기 어렵기 때문에 2단계까지만 적용해도 좋은 API 디자인이라고 볼 수 있으며, 이런 경우 HTTP API 라고도 부른다.
201 Created
로 명확하게 작성다음은 완성된 리차드슨의 성숙도 모델 예시이다.
균일한 인터페이스는 모든 RESTful 웹 서비스 디자인의 기본입니다. 이는 서버가 표준 형식으로 정보를 전송함을 나타냅니다. 형식이 지정된 리소스를 REST에서 표현이라고 부릅니다. 이 형식은 서버 애플리케이션에 있는 리소스의 내부 표현과 다를 수 있습니다. 예를 들어, 서버는 데이터를 텍스트로 저장하되, HTML 표현 형식으로 전송할 수 있습니다.
균일한 인터페이스에는 4가지 아키텍처 제약 조건이 있습니다.
요청은 리소스를 식별해야 합니다. 이를 위해 균일한 리소스 식별자를 사용합니다.
클라이언트는 원하는 경우 리소스를 수정하거나 삭제하기에 충분한 정보를 리소스 표현에서 가지고 있습니다. 서버는 리소스를 자세히 설명하는 메타데이터를 전송하여 이 조건을 충족합니다.
클라이언트는 표현을 추가로 처리하는 방법에 대한 정보를 수신합니다. 이를 위해 서버는 클라이언트가 리소스를 적절하게 사용할 수 있는 방법에 대한 메타데이터가 포함된 명확한 메시지를 전송합니다.
클라이언트는 작업을 완료하는 데 필요한 다른 모든 관련 리소스에 대한 정보를 수신합니다. 이를 위해 서버는 클라이언트가 더 많은 리소스를 동적으로 검색할 수 있도록 표현에 하이퍼링크를 넣어 전송합니다.
REST 아키텍처에서 무상태는 서버가 이전의 모든 요청과 독립적으로 모든 클라이언트 요청을 완료하는 통신 방법을 나타냅니다. 클라이언트는 임의의 순서로 리소스를 요청할 수 있으며 모든 요청은 무상태이거나 다른 요청과 분리됩니다. 이 REST API 설계 제약 조건은 서버가 매번 요청을 완전히 이해해서 이행할 수 있음을 의미합니다.
계층화된 시스템 아키텍처에서 클라이언트는 클라이언트와 서버 사이의 다른 승인된 중개자에게 연결할 수 있으며 여전히 서버로부터도 응답을 받습니다. 서버는 요청을 다른 서버로 전달할 수도 있습니다. 클라이언트 요청을 이행하기 위해 함께 작동하는 보안, 애플리케이션 및 비즈니스 로직과 같은 여러 계층으로 여러 서버에서 실행되도록 RESTful 웹 서비스를 설계할 수 있습니다. 이러한 계층은 클라이언트에 보이지 않는 상태로 유지됩니다.
RESTful 웹 서비스는 서버 응답 시간을 개선하기 위해 클라이언트 또는 중개자에 일부 응답을 저장하는 프로세스인 캐싱을 지원합니다. 예를 들어 모든 페이지에 공통 머리글 및 바닥글 이미지가 있는 웹 사이트를 방문한다고 가정해 보겠습니다. 새로운 웹 사이트 페이지를 방문할 때마다 서버는 동일한 이미지를 다시 전송해야 합니다. 이를 피하기 위해 클라이언트는 첫 번째 응답 후에 해당 이미지를 캐싱하거나 저장한 다음 캐시에서 직접 이미지를 사용합니다. RESTful 웹 서비스는 캐시 가능 또는 캐시 불가능으로 정의되는 API 응답을 사용하여 캐싱을 제어합니다.
REST 아키텍처 스타일에서 서버는 소프트웨어 프로그래밍 코드를 클라이언트에 전송하여 클라이언트 기능을 일시적으로 확장하거나 사용자 지정할 수 있습니다. 예를 들어, 웹 사이트에서 등록 양식을 작성하면 브라우저는 잘못된 전화번호와 같은 실수를 즉시 강조 표시합니다. 서버에서 전송한 코드로 인해 이 작업을 수행할 수 있습니다.
명제 URL 은 URI
는 참, URI 는 URL
이다는 거짓이며 127.0.0.1
은 로컬 pc localhost
와 같다.
도메인
을 검색하면 IP 를 확인할 수 있다.주요포트는 생략할 수 있지만 :3000 과 같은 임시포트는 명시해줘야한다.
클라이언트가 HTTP messages 양식에 맞춰 요청을 보내면, 서버도 HTTP messages 양식에 맞춰 응답합니다. HTTP messages에는 다음과 같은 두 가지 유형이 있습니다.
요청(Requests)과 응답(Responses)은 다음과 같은 유사한 구조를 가집니다.
이 중 start line과 HTTP headers를 묶어 요청이나 응답의 헤드(head)라고 하고, payload는 body라고 이야기합니다.
HTTP 요청은 클라이언트가 서버에 보내는 메시지입니다. Start line에는 세 가지 요소가 있습니다.
?
와 쿼리 문자열이 붙는 절대 경로입니다. POST, GET, HEAD, OPTIONS 등의 method와 함께 사용합니다. POST / HTTP 1.1
GET /background.png HTTP/1.0
HEAD /test.html?query=alibaba HTTP/1.1
OPTIONS /anypage.html HTTP/1.0
GET http://developer.mozilla.org/en-US/docs/Web/HTTP/Messages HTTP/1.1
CONNECT
와 함께 사용할 수 있습니다. CONNECT developer.mozilla.org:80 HTTP/1.1
OPTIONS
와 함께 별표(`) 하나로 서버 전체를 표현합니다.
OPTIONS * HTTP/1.1`요청의 Headers는 기본 구조를 따릅니다. 헤더 이름(대소문자 구분이 없는 문자열), 콜론( : ), 값을 입력합니다. 값은 헤더에 따라 다릅니다. 여러 종류의 헤더가 있고, 다음과 같이 그룹을 나눌 수 있습니다.
요청의 본문은 HTTP messages 구조의 마지막에 위치합니다. 모든 요청에 body가 필요하지는 않습니다. GET, HEAD, DELETE, OPTIONS처럼 서버에 리소스를 요청하는 경우에는 본문이 필요하지 않습니다. POST나 PUT과 같은 일부 요청은 데이터를 업데이트하기 위해 사용합니다. body는 다음과 같이 두 종류로 나눌 수 있습니다.
응답의 첫 줄은 Status line이라고 부르며, 다음의 정보를 포함합니다.
Status line은 HTTP/1.1 404 Not Found.
처럼 생겼습니다.
응답에 들어가는 HTTP headers는 요청 헤더와 동일한 구조를 가지고 있습니다. 대소문자 구분 없는 문자열과 콜론(:
), 값을 입력합니다. 값은 헤더에 따라 다릅니다. 요청의 헤더와 마찬가지로 몇 그룹으로 나눌 수 있습니다.
응답의 본문은 HTTP messages 구조의 마지막에 위치합니다. 모든 응답에 body가 필요하지는 않습니다. 201, 204와 같은 상태 코드를 가지는 응답에는 본문이 필요하지 않습니다. 응답의 body는 다음과 같이 두 종류로 나눌 수 있습니다.
chunked
로 설정되어 있으며, 파일은 chunk로 나뉘어 인코딩되어 있습니다.HTTP는 통신 규약일 뿐이므로, 상태를 저장하지 않는다. HTTP로 클라이언트와 서버가 통신을 주고받는 과정에서, HTTP가 클라이언트나 서버의 상태를 확인하지 않는다. 따라서 필요에 따라 다른 방법을 통해 상태를 확인 할 수 있다. (쿠키, 세션, API)
자바스크립트에서 DOM 을 조작할 수 있다. 때문에 필요한 데이터를 받아와 특정 데이터에 해당하는 DOM 을 조작하여 새로운 페이지를 불러오는 일 없이 HTML 을 변경할 수 있다.
기존에는 클라이언트에서 <form>
태그를 이용하여 요청을 보내면 서버에서는 응답으로 새로운 웹 페이지를 제공해 주어야 했다. 즉, 클라이언트에서 요청을 보낼 때 마다 새로운 페이지로 이동을 해야 했다.
하지만 Fetch 를 사용하면서 페이지를 이동하지 않고 서버로부터 필요한 데이터를 받아 올 수 있게 되었다. Fetch 는 사용자가 현재 페이지에서 작업을 하는 동안 서버와 통신할 수 있도록 하는데 요청과 응답이 오가는 동안 모든 동작을 멈추는게 아닌 계속해서 페이지를 사용할 수 있도록 비동기적인 방식을 사용하기 때문에 새로운 페이지의 요청 없이 현재 페이지에서 필요한 데이터를 받아 올 수 있게 되었다.
결국 AJAX로 인해 SPA (Single Page Application) 가 가능하게 되었다.