REST API

잘 디자인된 API의 경우 플랫폼에 독립되어야 하고 확장성을 지녀야한다.

REST API

REST(Representational State Transfer)는 어떤 기본 프로토콜과도 독립적이며 HTTP에 연결될 필요가 없다.
하지만 일반적인 REST API는 프로토콜로 HTTP를 사용한다.

RESTful API 디자인 원칙

  • REST API는 리소스를 중심으로 디자인된다.
    또한 클라이언트에 엑세스 할 수 있는 모든 종류의 개체, 데이터 또는 서비스가 리소스에 포함된다.

  • 리소스마다 해당 리소스를 고유하게 식별하는 URI인 식별자가 있다.
    예를 들어 HTTP기반의 특정 고객 주문의 URI는 다음과 같다.

1
https://adventure-works.com/orders/1
  • 클라이언트와 서버가 리소스의 표현을 교환한다.
    주로 JSON 형식을 교환한다. 위의 URI에 대한 GET 요청은 이러한 데이터를 반환한다.
1
{ "orderId": 1, "orderValue": 99.9, "productId": 1, "quantity": 1 }
  • 리소스에 표준 HTTP 메서드를 통해 작업을 지시한다.
    대표적으로 GET,POST,PUT,PATCH,DELETE등이 있다.

  • Stateless이다. HTTP 요청은 독립적이고 임의순서로 발생하기 때문이다.
    서버는 정보를 리소스에만 저장되고 요청이 들어오면 해당하는 데이터를 반환하면 되기때문에 확장성이 우수하다.

  • 하이퍼미디어 링크에 따라 구동된다.
    고객 정보를 가져오거나(GET), 업데이트(PUT) 하는 링크를 포함한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"orderID": 3,
"productID": 2,
"quantity": 4,
"orderValue": 16.6,
"links": [
{
"rel": "product",
"href": "https://adventure-works.com/customers/3",
"action": "GET"
},
{
"rel": "product",
"href": "https://adventure-works.com/customers/3",
"action": "PUT"
}
]
}

REST API 디자인

  • REST API는 리소스를 구성으로 디자인해야 한다.
    즉 리소스 URI는 동사(작업)이 아닌 명사(리소스)를 기반으로 해야한다

    1
    2
    3
    https://adventure-works.com/orders // Good

    https://adventure-works.com/create-order // Avoid
  • REST API의 엔티티는 컬렉션(주문, 고객)등으로 그룹화된다.
    컬렉션은 별도의 리소스이며 고유한 URI가 있어야한다.
    다음은 주문 컬렉션의 URI이다.

    1
    https://adventure-works.com/orders
  • 컬렉션 하위 요소들에 URI에 일관적인 명명 규칙을 적용하여 관리한다.
    다음은 주문번호가 5인 주문이다.
    orders/{id}와 같은 형식으로 관리한다.

    1
    https://adventure-works.com/orders/5

HTTP 메서드를 기준으로 API 작업 정의

GET

URI에서 리소스의 표현을 검색한다.
리소스의 세부정보를 응답메시지의 본문에 담는다.

POST

URI에 새 리소스를 만든다.
요청 메시지의 본문에 담긴 리소스를 새로 만든다.
실제로 리소스를 만들지 않는 작업을 수행하기도 한다(로그인 등)

PUT

URI에 리소스를 만들거나 대체한다.
요청 메시지의 본문에 만들 또는 업데이트할 리소스를 담는다.

PATCH

리소스를 수정(부분 업데이트)한다.
요청 메시지의 본문에 리소스에 적용할 변경 내용을 담는다.

DELETE

URI의 리소스를 제거합니다.

HTTP 의미 체계 준수

HTTP 사양을 준수하기 위한 고려사항이 몇 가지 있다.

미디어 유형

리소스 표현의 형식을 요청 또는 응답의 Content-Type 헤더를 통해 지정한다.
미디어 유형을 지원하지 않을 경우 415(지원되지 않는 미디어) 에러를 반환한다.

1
Content-Type:application/json; charset=utf-8

클라이언트 요청에는 Accept 헤더를 통해 서버에서 받는 미디어 유형을 지정할 수 있다.

서버에서 해당 미디어 유형을 일치시킬 수 없을경우 406(허용되지 않음)을 반환한다.

GET

성공할 경우 200(정상)찾을 수 없을 경우 400(찾을 수 없음)을 반환한다.

POST

새 리소스를 만드는 경우 201(만들어짐)을 반환한다.
새 리소스를 만들지 않는 경우 200을 반환한다.
반환할 경과가 없는 경우 204(내용 없음)을 반환한다.
새 리소스의 URI는 응답의 Location헤더에 포함된다.

PUT

PUT은 POST와 같은 HTTP 상태코드를 반환한다.
하지만 기존 리소스를 업데이트 할 수 없는 경우 409(충돌)을 반환한다.

PATCH

JSON 패치 혹은 JSON 병합 패치가 있다.

지원되지 않는 패치 형식일경우 415를 반환한다.
패치 문서의 형식이 잘못되었을 경우 400을 반환한다.
패치문서가 유효하지만 리소스에 적용할 수 없을 경우 409를 반환한다.

JSN 병합 패치

변경 또는 추가할 필드의 하위집합만 포함한다.
혹은 null값을 지정하여 필드를 삭제할 수 있다.( 원래 null값을 지닌다면 적합하지 않다.)

미디어 유형은 application/merge-path+json이다.

JSON 패치

명식적으로 null값을 포함할 수 있는 경우 JSON패치가 적절하다.
작업에는 추가, 제거, 바꾸기, 복사 및 텍스트(유효성검사)가 포함된다.

미디어 유형은 application/json-patch+json이다.

DELETE

삭제에 성공하면 204(콘텐츠 없음)을 반환하고 응답 본문에는 정보를 포함하지 않는다.
리소스가 없는경우 404를 반환한다.

데이터 필터링

데이터 필터링의 경우 쿼리 스트링을 이용하여 처리한다.
다음 URI는 최대 항목수와 컬렉션의 시작 오프셋을 지정하는 쿼리 스트링이다.

1
/orders?limit=25&offset=50

ref

(Web API디자인)[https://docs.microsoft.com/ko-kr/azure/architecture/best-practices/api-design]

HTTP

HTTP는 HTML 문서와 같은 리소스를 가져올 수 있도록 해주는 프로토콜이다.

클라이언트 - 서버 프로토콜

  • 클라이언트는 서버에게 서비스를 요청하는 사용자나 컴퓨터이다.

  • 서버는 서버 프로그램이 실행되고 있는 하드웨어이다.

  • 클라이언트 - 서버 프로토콜은 수신자측에 의해 요청이 초기화되는 프로토콜이다.

응답과 요청

  • 클라이언트와 서버가 개별적인 메시지 교환에 의해 통신한다.

  • 클라이언트에 의해 전송되는 메시지를 요청(request) 이라고 부른다.

  • 서버에서 응답으로 전송되는 메시지를 응답(response)라고 부른다.

HTTP

  • TCP 혹은 암호화된 TCP 연결인 TLS를 통해 전송된다.

  • 확장성으로 인해 POST 하기 위해서도 사용된다.

HTTP 기반 시스템의 구성 요소

  • 각각의 개별적인 요청들은 서버로 보내지며 서버는 요청을 처리하고 response라고 불리는 응답을 제공한다.

  • 요청과 응답 사이에는 게이트웨이 또는 캐시 역할을 하는 프록시등이 있다.
    (cdn등…)

프록시

  • 간단하게 미들웨어의 역할을 하는 컴퓨터로 생각하면 된다.

  • 다음과 같은 기능들을 한다.

    • 캐싱
    • 필터링
    • 로드 밸런싱
    • 인증
    • 로깅

HTTP의 특징

간단하다.

  • 사람이 읽을 수 있으며 간단하다.
  • HTTP 메시지는 사람이 읽고 이해할 수 있다.

확장 가능하다.

  • 헤더를 통해 여러 기능을 확장할 수 있다.

상태가 없고 세션이 있다.

  • stateless로 작동한다. 상태를 유지하지 않기 때문에 클라이언트의 요청이 갑자기 많아져도 안정적이다. 또는 서버증설을 통해 쉽게 해결할 수 있다.

  • 기본적으로 stateless지만 세션이나 쿠키등으로 상태를 유지한다.(로그인이나 인증 등의 로직을 위해)

HTTP와 연결

  • 기본적으로 TCP/IP는 한 번 요청하고 응답을 보내고 나서는 연결을 끊는다.

  • 이러한 비효율성을 해결하기위해 HTTP/1.1은 파이프라이닝 개념을 통해 지속적인 연결 개념을 도입했다.(Connection 헤더를 사용해 부분적으로 제어 가능하다.)

  • HTTP/2는 단일 연결상에서 메시지를 다중 전송할 수 있도록 하였다.

HTTP로 제어할 수 있는 것

캐시

  • 헤더를 통해 문서가 캐시되는 방식을 제어할 수 있다.

origin

  • cors에서 많이 고통받던 그 녀석이다.
  • 동일한 origin으로 부터 온 페이지만이 정보에 접근할 수 있지만 헤더 설정을 통해 완화할 수 있다.

인증

  • 헤더나 쿠키를 통해 제어할 수 있다.

프록시와 터널링

  • 프록시를 제어할 수 있다.

세션

  • 서버 상태를 요청과 연결하도록 한다.
  • stateless인 프로토콜임에도 state를 유지하며 동작할 수 있다.

HTTP 흐름

HTTP를 통해 클라이언트가 서버와 통신할 때 다음과 같은 과정을 거친다.

  1. TCP 연결을 연다. 요청을 보내거나 응답을 받는데에 사용된다.
  2. HTTP 메시지를 전송한다.
  3. 서버에 의해 전송된 응답을 읽어들인다.
  4. 연결을 닫거나 다른 요청들을 위해 재사용한다.

HTTP 메시지

HTTP 메시지의 요청과 응답은 각자의 형식을 가지고 있다.

요청

요청은 다음과 같은 요소들로 구성된다

HTTP 메서드

클라이언트가 수행하고자 하는 동작이나 options와 head와 같은 명사이다.

가져오려는 리소스의 경로

프로토콜(http),도메인, tcp포트(http의 경우 80 포트)를 제거한 리소스의 URL이다.

그 외
  • HTTP 프로토콜의 버전
  • 여러 헤더
  • 메서드를 위한 전송된 리소스를 포함하는 본문(request.body)

응답

  • HTTP 프로토콜의 버전
  • 요청의 성공 여부와 상태 코드
  • 상태코드의 설명을 나타내는 메시지(response 안에 담아서 보낸다.)
  • HTTP 헤더들.
  • 가져온 리소스가 포함되는 본문.

주로 request의 본문과 메시지를 같이 보내는 것이 좋은 것 같다.
추가로 error code나 메시지를 객체로 정의하여 보내는 경우도 있다.

그 외

주로 데이터를 json으로 주고받게 되는데 다음과 같은 함수들이 있다.

JSON.parse()

  • 문자열을 JSON으로 구문 분석한다.

JSON.stringify()

  • JSON 문자열을 반환한다.

추가

  • JSON.stringify()후 JSON.parse()를 통해 깊은 복사를 할 수 있다.

ref

HTTP overview

클라이언트 서버 통신

HTTP 메시지 구조