REST API 정리
해당 글 작성일자 : 2019년 말 추정
목차
-
3줄 요약
-
개요
-
구성
-
특성
-
설계
-
URI 경로 설계 관련
-
HTTP-Method 설계 관련
-
HTTP Response 코드 설계 관련
-
메타데이터 설계 관련
-
오류 처리
-
캐시
-
보안
-
놓치지 마세요
-
숙제
-
-
참고문헌
3줄 요약
REST API는 효율적인 HTTP API를 설계/개발하기 위한 "HTTP API 구현 방법론"이다.
보통의 개발자는 REST API Uniform Interface 4개 특성 중 2개 밖에 충족하지 못 한다.
REST API에 대해 잘 알고 있는 독자는 "설계-놓치지 마세요" 에서 충족 못하는 2개를 확인할 수 있다.
개요
해당 문서를 작성한 주된 이유는DEVIEW 2017 REST API 관련 발표 덕분이다.
로이필딩의 박사학위 논문에서 처음 소개됐다. 웹의 본래 설계의 우수성을 많이 사용하지 못하고 있다 판단했으며, 웹의 장점을 최대한 활용할 수 있는 아키텍쳐를 소개했다. 그것이 바로 Representational State Transfer(표현 상태 전이, REST)이다.
-
REST API는 REST 아키텍쳐 스타일을 따르는 API이다.
-
REST는 분산 하이퍼미디어 시스템을 위한 아키텍쳐 스타일이다.
-
아키텍쳐 스타일은 제약조건의 집합이다.
-
즉, 모든 규칙을 지켜야 REST API라 칭할 수 있다.
-
REST 구성 스타일은 아래와 같다.
-
Client-server
-
Stateless
-
Cache
-
Uniform interface(중요)
-
Layered system: 클라이언트는 서버에 직접/게이트웨이 경유를 통해 연결되었는지 모른다(웹의 특징).
-
Code-on-demand(optional): 클라이언트가 보낸 코드를 서버에서 실행할 수 있는 것
-
REST API는 URI구조, HTTP Method, 메타데이터를 활용하여, 사용자에게 직관적인 API를 제공하는 것을 목표로 하고 있다.
URI(Uniform Resource Identifier)는 REST API에서 리소스를 식별 및 표현할 때 표현한다. 즉, URI에 포함되는 모든 글자는 리소스의 유일한 식별자로 적용한다. REST API를 설계할 때 빠질 수 없는 것 중 하나는 URI 계층 설계이다. URI는 RFC 3986 문서에서 문법을 확인할 수 있다.
구성
자원(Resource) - URI
-
자원을 구별하는 ID는 ‘/groups/:group_id’와 같은 HTTP URI이다.
-
Client는 URI를 이용해서 자원을 지정하고 해당 자원의 상태(정보)에 대한 조작을 Server에 요청한다.
행위(Verb) - HTTP Method
-
HTTP 프로토콜의 Method를 사용한다.
-
HTTP 프로토콜의 Method 범주 밖의 행위는 POST:$행위명을 지정한다(예: POST: /getLoginSessionDatas).
표현(Representations)
-
Representation은 리소스의 특정 시점의 상태를 반영하고 반환한 것이다.
-
Representation의 구성은 1) HTTP Body(representation data)와 2)Content-type:text/plain, Content-Language:en”(representation metadata)으로 구성되어있다. 즉, HTTP Header와 Body를 포함시켜 Representation이라 칭한다.
-
Representation MetaData: Content-Type / Content-Encoding / Content-Language / Content-Location
-
REST에서 하나의 자원은 JSON, XML, TEXT, RSS 등 여러 형태의 Representation으로 나타내어질 수 있다.
특성
유니폼 인터페이스(Uniform Interface)
-
REST API는 HTTP 표준만 준수하면 기술, 환경, 언어에 종속적이지 않다. 모두 같은 인터페이스를 제공할 수 있다.
무상태(Stateless)
-
본래 HTTP 프로토콜은 무상태 프로토콜이다. 그러나, 로그인, 장바구니 등과 같은 상태 지속성이 필요하여 쿠키, 세션등을 사용하였다.
-
REST API는 클라이언트의 상태 정보를 저장할 필요가 없으며, API 요청만 처리하면 된다.
캐쉬 가능(Cacheable)
-
HTTP의 캐시를 그대로 사용할 수 있다.
클라이언트 서버 구조
-
서버에서 API를 제공한다.
Layered System, Code on Demand 등이 존재한다.
설계
1. URI 경로 설계 관련
1.1. URI 형태 및 규칙
-
형태
URI = scheme “ :// ” authority “ / ” path [“ ? ” query] [“ # ” fragment ] |
-
규칙
-
슬래시 구분자는 계층 관계를 나타내는데 사용한다.
-
URI의 마지막은 슬래시가 존재하지 않는다.
-
하이픈을 통해 URI 가독성을 높인다. URI에서의 문장 공백을 하이픈으로 대체한다.
-
URI에는 언더라인(_)을 사용하지 않는다.
-
URI 경로에는 소문자만 사용한다. RFC 3986은 URI 스키마와 호스트를 제외하고는 대소문자를 구별하도록 규정하고 있다. 즉, 아래와 전자 후자는 같은 의미이다.
-
-
-
파일 확장자는 URI에 포함시키지 않는다. 확장자는 미디어 타입에 의존한다. Context-Type헤더를 통해 전달한다.
-
도메인과 버전정보를 아래와 같은 지정을 권고한다(MS에서 권고하는 형식이다.
-
https://api.contoso.com/v1.0/people/jdoe@contoso.com/inbox |
1.2. URI의 종류
-
도큐먼트: 객체 인스턴스나 데이터베이스 레코드와 유사한 단일 개념이다. 예는 아래와 같다.
-
컬렉션: 서버에서 관리하는 디렉터리 리소스이다. 도큐먼트의 집합 또는 객체의 집합이다. 예는 아래와 같다.
-
컨트롤러: REST API CRUD에 매핑하지 못한 명령어를 표현할 때 사용한다. 컨트롤러 이름은 URI 경로의 제일 마지막 부분에 표시하며 자식 리소스가 존재하지 않는다. 예는 다음과 같다.
1.3. URI 경로 설계 규칙
-
일관성, 직관적인 URI 구조를 잡는다.
-
URI의 최대 길이는 2000 character이다(디펙토 표준).
-
계층적 구조를 분명하게 표현해야 한다.
-
단일 개념을 표현할 때는 단수 명사 또는 명사구를 지정한다.
-
컬렉션과 같은 집합체를 표현할 때는 복수 명사 또는 복수 명사구를 지정한다.
-
컨트롤러 이름은 동사나 동사구를 사용해야한다.
-
경로 부분 중 변하는 부분은 유일한 값이어야 한다. 예는 다음과 같다. 아래의 중괄호는 변하는 값이며, 유일한 값이어야 한다.
http://example.com/groups/{number1} http://example.com/groups/{number1}/users/{ehdvudee} |
-
CRUD 기능을 나타내는 것은 URI에 사용하지 않는다. CRUD는 HTTP Method에서 표현할 수 있다.
1.4. URI 쿼리 스트링
-
리소스 식별할 때 도움을 주거나, 기타 보조 수단으로 활용할 수 있다. 예는 아래와 같다.
GET /users?role=admin POST /users/search?age=25&sex=1 |
2. HTTP-Method 설계 관련
2.1. 기본
REST API 리소스 모델에서 각 HTTP Method는 고유한 의미가 존재한다.
-
GET: 조회(리소스의 상태 표현)
-
POST: 생성(컬렉션에 새로운 리소스 생성 또는 컨트롤러 실행)
-
PUT: 전체 갱신/수정
-
PATCH: 부분 갱신/수정
-
DELETE: 삭제(리소스를 제거)
-
HEAD: 리소스 상태에 대한 메타데이터 조회
2.2. 규칙
-
컨트롤러를 실행할 때는 POST 메소드를 사용한다. 예는 다음과 같다.
-
응답 헤더를 가져올 때는 반드시 HEAD 메서드를 사용한다. 리소스 존재 여부만 확인할 때 보통 사용한다.
-
GET 메소드는 리로스 상태 표현을 얻는데 사용해야 한다.
-
PUT/PATCH 메소드는 변경 가능한 리소스를 갱신하는데 사용해야 한다.
-
POST 메소드는 새로운 리소스를 만드는데 사용해야 한다.
-
POST 메소드를 성공적으로 반환 받을 때, Response Code는 201(Created)이며, Location 헤더에 생성된 URI를 적재한다.
-
또는 Response Code 200을 지정하고, 생성한 값을 Body에 적재하여 반환한다.
-
DELETE 메소드는 부모 이하의 리소스를 삭제하는데 사용해야 한다.
3. HTTP Response 코드 설계 관련
REST API의 응답 상태 여부는 HTTP Code를 통해 확인할 수 있어야 한다. 응답 상태 코드 범주는 아래와 같다.
범주 |
설명 |
1xx: 정보 |
전송 프로토콜 수준의 정보 교환 |
2xx: 성공 |
클라이언트 요청이 성공적으로 수행 |
3xx: 재전송 |
클라이언트는 요청을 완료하기 위해 추가적인 행동을 취해야 함 |
4xx: 클라이언트 오류 |
클라이언트의 잘못된 요청 |
5xx: 서버 오류 |
서버쪽 오류로 인한 상태 코드 |
HTTP 응답 코드는 다음과 같이 사용할 수 있다.
-
200(OK): 일반적인 요청 성공, 200 응답 바디에 에러를 전송하면 안된다.
-
201(Created): 성공적으로 리소스를 생성했을 때 사용한다.
-
202(Accepted): 비동기 처리가 성공적으로 시작되었음을 알릴 때 사용한다. 컨트롤러 리소스만 해당 응답을 반환할 수 있다.
-
301(Moved Permanently): REST API 리소스 모델을 재설계했을 때 반환한다. 응답 Location 헤더에 새로운 URI를 기술해야한다.
-
304(Not Modified): 네트워크 대역폭을 절약할 때 사용한다. 리소스에 정보에 대해 이미 클라이언트가 갖고 있을 때 반환한다.
-
400(Bad Request): 일반적인 요청실패에 사용한다. 보통 클라이언트가 인자를 잘못 보낼 때 사용한다.
-
401(Unauthorized): 클라이언트에 인증에 문제가 있을 때 사용한다. 인증 안/못/잘못 했을 때 반환한다.
-
403(Forbidden): 인증과 관계없이 인가되지 못한 사용자에 대해 거절한다.
-
404(Not Found): URI에 해당하는 리소스가 존재하지 않을 때 반환한다.
-
405(Mehotd Not Allowed): 해당 URI에 대해 HTTP 메소드가 지원하지 않을 때 사용한다.
-
406(Not Acceptable): 요청된 리소스 미디어 타입을 제공하지 못할 때 사용한다. 예를 들어, 클라이언트가 HTTP Request 요청에 Accept헤더에 application/xml를 지정하였고, 서버는 해당 사항을 처리 못할 때 이와 같이 반환한다.
-
415(Unsupported Media Type): 요청한 Body의 미디어 타입을 처리하지 못할 때 사용한다. 예를 들어, 클라이언트가HTTP Request 요청에 Content-Type 헤더에 application/xml를 지정하였고, 서버는 해당 사항을 처리 못할 때 이와 같이 반환한다.
-
500(Internal Server Error): 서버가 예상되지 않은 오류가 생길 때 반환한다.
4. 메타데이터 설계 관련
4.1. HTTP 헤더
-
Content-Type 사용을 통해 미디어 타입을 식별 및 처리한다.
-
Context-Length 사용을 통해, 클라이언트는 Body를 전부 읽었는지 확인할 수 있다.
-
Location 사용을 통해 변경/생성된 URI 표현
-
Cache-Control, Expires, Date, Pragma, ETag, Last-Modified 사용을 통해 캐시 활용
4.2. 미디어 타입
HTTP 요청이나 응답 메시지 바디안에 있는 데이터의 형태를 식별할 때 사용하는 것을 미디어 타입, Content-Type이라 칭한다. 미디어 타입의 문법은 아래와 같다.
type “/” subtype01( “;” parameter) |
type 값은 application, image, multipart 등이 있다. REST API에서 많이 사용하는 타입은 아래와 같다.
Content-type: application/json; charset=UTF-8 |
미디어 타입은 Content-Type과 Accept을 통해 다음과 같이 많이 활용할 수 있다.
-
서버/클라이언트 Content-Type을 통해 본인이 구성한 Body의 미디어 타입을 서버에 알려줄 수 있다.
-
서버는 클라이언트가 보낸 Content-Type에 맞게 데이터를 처리할 수 있다.
-
클라이언트는 Accept를 통해 본인이 원하는 미디어 타입을 서버가 반환하도록 요청할 수 있다.
또한, REST API 서버는 아래와 같은 지원을 허용할 수 있다.
GET /users?accept=application/xml |
서비스의 HTTP Response 데이터 포멧 기본 값은 JSON을 권고한다. 또한 변수명은 카멜표기법을 원칙으로 한다.
사용자 정의 미디어 타입
5. 오류 처리
권고안 및 규칙은 아래와 같다.
-
상황에 맞는 HTTP Status Code를 지정해야 한다.
-
Body는 아래와 같이 지정하는 것을 권고한다.
HTTP 400 Err { “error”: { “code”:”glaso-00010”, “message”: “password is not defined”, “target”:”password”, “details”:[“password is not defined”, “password validation Exception”] “innerError”: { // 재귀 } } } |
5. 캐시
5.1. HTTP 프로토콜 캐시의 한계
-
동적 리소스에 대해 캐시를 적용하는 것은 정말 힘들다. 예를 들어, 정적 리소스(css/js)의 경우, 캐시를 적용하기 쉽다.
-
HTTP의 캐시의 경우, Last-Modified, E-Tag를 활용할 수 있다. 다만, 이 캐쉬들은 네트워크 대역폭을 감소시키는 것이지, 요청의 처리에 대한 감소는 존재하지 않는다.
-
즉, ETag를 사용하면, 304 Not Modified를 반환 받는다. 그러나, 서버는 결과만 반환하지 않을 뿐, 요청에 대한 처리는 진행한다. 또한, 클라이언트 304를 받을 경우, 클라이언트 캐시에서 해당 값을 불러온다.
5.2. 너무 불편하지 않은가?? 쉽게 가자. 어플리케이션 캐시를 진행한다.
-
클라이언트 캐시가 아닌 서버 캐시를 진행한다.
-
Java를 사용한다면 EHCache를 사용할 수 있다.
-
만약 Spring이면 더 쉬울 수 있다.
6. 보안
필요사항
-
교차 사이트 리소스 공유(CORS) 허용이 필요하다.
-
CORS를 허용하기 때문에 인증 절차가 필요하다.
-
REST API기능을 제공할 때 식별/인증/인가 절차는아래와같이활용할 수 있다.
-
OAuth2.0 / 엑세스 토큰(JWT) / API Key / Basic Auth(ID/PW) / 2WayTLS / WhiteList
-
7. 놓치지 마세요
로이필딩은 시중에 나와있는 REST API는 REST하지 않다고 표현하였다. MS의 REST API 가이드 문서 또한 REST 하지 않다고 얘기했으며, CMIS (Content Management Interoperability Services) CMS 표준 또한 REST를 지원하지만 그것은 REST하지 않다고 얘기하였다. 로이 필딩은 REST API의 모든 제약조건을 지켜야지 그것을 비로소 REST API라고 칭할 수 있다 하였다. 그래서 보통의 사람들은 REST API를 칭할 때, RESTful API 또는 REST Like API라는 용어들을 사용한다.
시중에 나와있는 REST API는 어떤 것이 결여되었는가?
7.1. Self-descriptive messages
-
메시지는 스스로 설명한다는 의미이며, Self-descriptive는 Uniform Interface의 특성 중 하나이다.
-
준수사항
-
HTTP 헤더 Content-Type에 application/json + 확장 미디어 타입을 지정한다.
-
미디어 타입을 통해 Body를 이해할 수 있다.
-
HTTP Method를 통해 API의 행동을 알 수 있어야한다.
-
URI를 통해 API의 대상을 알 수 있어야한다.
-
7.2. HATEOAS(헤이티오스, Hypermedia As The Engine Of Application state)
-
어플리케이션의 상태는 Hyperlink를 통해 이용해 전이되어야 한다.
-
링크를 제공하여, 하이퍼미디어 시스템을 제공해야한다.
7.3. Self-descriptive, HATEOAS의 독립적 진화(확장성)에 어떻게 도움이 될까?
-
확장 가능한 커뮤니케이션, 서버나 클라이언트가 변경해도 언제나 self-descriptive하다.
-
어디서 어디로 전이가 가능한지 미리 결정되지 않는다. 어떤 상태로 전이가 완료되고 나서야 그 다음 전이될 수 있는 상태가 결정된다. 즉, 링크를 동적으로 변경할 수 있다.
7.4. Self-descriptive, HATEOAS 만족의 예
GET /todos HTTP/1.1 Host: example.org
HTTP/1.1 200 OK Content-Type: text/html
<html> <body> <a href=https://todos/1>집에 가기</a> <a href=https://todos/2>회사 가기</a> </body> </html> |
1. 응답 메시지의 Content-Type을 보고 media type이 text/html임을 확인한다. 2. HTTP 명세에 media type은 IANA에 등록되어있다고 하므로, IANA에서 text/html의 설명을 찾는다. 3. IANA에 따르면 text/html의 명세는 http://www.w3.org./TR/html 이므로 링크를 찾아가 명세를 해석한다. 4. 명세에 모든 태그의 해석방법이 구체적으로 나와있으므로 이를 해석하여 문서 저자가 사용자에게 해 주려고 했던 모든 일들을 해줄 수 있다. 5. 즉, Self-descriptive messages이다. 6. 또한, a 태그를 이용해 표현된 링크를 통해 다음 상태로 전이될 수 있으므로 HATEOAS를 만족한다. |
7.5. Self-descriptive, HATEOAS 불만족의 예
GET /todos HTTP/1.1 Host: example.org
HTTP/1.1 200 OK Content-Type: application/json
[ {“id”: 1, “title”:”회사 가기”}, {“id”: 2, “title”:”집에 가기”} ] |
1. 응답 메시지의 Content-Type을 보고 media type이 application/json임을 확인한다. 2. HTTP 명세에 media type은 IANA에 등록되어있따고 하므로, IANA에서 application/json의 설명을 찾는다. 3. IANA에 따르면 application/json의 명세는 draft-ietf-jsonbis-rfc7159bis-04이므로 링크를 찾아가 명세를 해석한다. 4. 명세에 json 문서를 파싱하는 방법이 명시되어있으므로 성공적으로 파싱에 성공한다. 그러나 “id”가 무엇을 의미하고, “title”이 무엇을 의미하는지 알 방법은 없다. 5. 즉, id와 title을 이해하지 못하기 때문에 Self-descriptive messages가 아니다. 6. 또한, 다음 상태를 전이할 수 없기 때문에, HATEOAS를 만족하지 못한다. |
7.6. 위의 불만족을 만족으로 변경
GET /todos HTTP/1.1 Host: example.org
HTTP/1.1 200 OK Content-Type: application/vnd.todos+json
[ {“id”: 1, “title”:”회사 가기”}, {“id”: 2, “title”:”집에 가기”} ] |
1. 미디어 타입을 정의한다[1]. 2. 미디어 타입 문서를 작성한다. 이 문서에 “id”가 뭐고 “title”이 뭔지 의미를 정의한다. 4. 이 메시지를 보는 사람은 명세를 찾아갈 수 있으므로 이 메시지의 의미를 온전히 해석할 수 있다(해당 문서는 별도의 링크 또는 IANA를 통해 확인할 수 있어야 한다.). 5. Content-Type의 명확한 지정, Links를 통한 HATEOAS Driven 방식 |
8. 숙제
REST API 트랜잭션 대응
-
REST API 중, POST HTTP Method의 경우, Idempotent하지 않기 때문에, 1개의 트랜잭션에 2개 이상의 POST API일 경우, 트랜잭션 제어가 필요하다.
-
일반적인 JDBC API를 통해 트랜잭션을 제어하지 못한다.
-
JTA(Java Transaction API), TCC(Try-Confirm/Cancel)과 같은 기술을 사용하여, 글로벌 트랜잭션에 대해 대응할 수 있다
참고문헌
-
HANBIT_REST_API_Design_Rulebook
-
https://github.com/Microsoft/api-guidelines/blob/master/Guidelines.md
-
https://www.youtube.com/watch?v=_SikP7FwZhY&feature=youtu.be
[1] vnd는 벤더 고유 미디어 타입이다. 공통 미디어 타입과는 달리 어플리케이션 고유의 메타데이터를 전달할 수 있다.
'개발관련 > (과거)메모' 카테고리의 다른 글
PostgreSQL 서버 중요 설정 정보 (0) | 2021.01.18 |
---|---|
다양한 스프링 활용기(지속적인 업데이트 - 수정:20.12.31) (0) | 2020.12.31 |
Java Performance를 올리는 코딩 Best Practice (0) | 2020.05.20 |
IntelliJ(JetBrain) 단축키 표(모음) 공유 (1) | 2020.05.18 |
Tomcat 튜닝 가이드 (0) | 2020.05.14 |