REST API 설계 원칙
1. REST(Representational State Transfer)
- URI를 통해 자원을 표시하고, HTTP Method를 이용하여 해당 자원의 행위를 규정하여 그 결과를 받는 것을 의미한다.
- 구성
종류 | 설명 |
자원(Resource) | URI |
행위(Verb) | HTTP Method |
표현(Representations) | - |
1.1 REST 특징
특징 | 설명 |
Uniform | - Uniform Interface - URI로 지정한 리소스에 대한 조작을 통일되고 한정적인 인터페이스로 수행하는 아키텍처 스타일을 의미한다. |
Stateless | - 무상태성 성격을 갖는다. 작업을 위한 상태 정보를 따로 저장하고 관리하지 않는다. - 세션 정보나 쿠키 정보를 별도로 저장하고 관리하지 않기 때문에 API 서버는 들어오는 요청만을 단순히 처리하면 된다. 이러한 이유로 서비스의 자유도가 높아지고 서버에서 불필요한 정보를 관리하지 않음으로써 구현이 단순해진다. |
Cacheable | - HTTP라는 기존 웹 표준을 그대로 사용하기 때문에, 웹에서 사용하는 기존 인프라를 그대로 활용할 수 있다. 따라서 HTTP가 가진 캐싱 기능 적용이 가능하다. - HTTP 프로토콜 표준에서 사용하는 Last-Modified 태그나 E-Tag를 이용해 구현할 수 있다. |
Self-descriptiveness | REST API 메시지만 보고도 이를 쉽게 이해할 수 있는 자체 표현 구조로 되어 있다. |
Client - Server 구조 | - REST서버는 API 제공, 클라이언트는 사용자 인증이나 컨텍스트(세션, 로그인 정보) 등을 직접 관리하는 구조로 각각의 역할을 확실하게 구분한다. - 클라이언트와 서버에서 개발해야 할 내용이 명확해지고 서로 간 의존성이 줄어든다. |
계층형 구조 | - REST 서버는 다중 계층으로 구성될 수 있으며 보안, 로드 밸런싱, 암호화 계층을 추가해 구조 상의 유연성을 둘 수 있고 PROXY, 게이트웨이 같은 네트워크 기반의 중간 매체를 사용할 수 있게 한다. |
2. REST API 설계 원칙
① URI는 정보의 리소스를 표현해야 한다.
// REST를 제대로 적용하지 않은 URI 예시
GET /members/delete/1
- 행위에 대한 표현이 아닌 리소스 표현하는데 중점을 두어야 한다.
- 리소스명은 동사보다는 명사를 사용한다.
② 리소스에 대한 행위는 HTTP Method로 표현한다.
- GET, POST, PUT, DELETE 등
// REST 적용 예시 1
GET /members/delete/1 (X)
DELETE /members/1 (O)
// REST 적용 예시 2
GET /members/show/1 (X)
GET /members/1 (O)
// REST 적용 예시 3
GET /members/insert/3 (X)
POST /members/3 (O)
③ 슬래시 구분자(/)는 계층 관계를 나타내는데 사용한다.
④ URI 마지막 문자로 슬래시(/)를 포함하지 않는다.
⑤ 하이픈(-)은 URI 가독성을 높이는데 사용할 수 있다.
- URI를 쉽게 읽고 해석하기 위해, 불가피하게 긴 URI 경로를 사용하게 된다면 하이픈을 사용해 가독성을 높일 수 있다.
⑥ 언더바(_)는 URI에 사용하지 않는다.
- 보기 어렵거나 밑줄 때문에 문자가 가려지는 가독성 문제가 발생한다. 대신 하이픈을 사용한다.
⑦ URI 경로에는 소문자를 사용한다.
- 대소문자에 따라 다른 리소스로 인식하기 때문이다.
- RFC3986(URI 문법 형식)은 URI 스키마와 호스트를 제외하고는 대소문자를 구별하도록 규정하고 있다.
⑧ 파일 확장자는 URI에 포함시키지 않는다.
- REST API에서는 메시지 바디 내용의 포맷을 나타내기 위한 파일 확장자를 URI 안에 포함시키지 않는다. 대신 Accept header를 사용한다.
// REST 적용 예시
http://restapi.example.com/members/soccer/345/pthoto.jpg (X)
GET /members/soccer/345/photo HTTP/1.1 (O)
Host: restapi.example.com
Accept: image/jpg
2.1 HTTP Method
- 종류
종류 | 설명 |
GET | - 리소스를 조회한다. - 서버에 전달하고 싶은 데이터는 qeury(쿼리 파라미터, 쿼리 스트링)를 통해서 전달한다. - 메시지 바디를 사용해서 데이터를 전달할 수 있지만, 지원하지 않는 곳이 많아서 권장되지 않는다. |
POST | - 새 리소스를 생성할 때 사용한다. - 메시지 바디를 통해 서버로 요청 데이터를 전달하고 처리하는데 사용한다. 단순히 데이터를 생성하거나 변경하는 것을 넘어서 프로세스를 처리해야 하는 경우가 해당한다. POST의 결과로 항상 새로운 리소스가 생성되는 것은 아니다. - JSON으로 조회 데이터를 넘겨야 하는데 GET 메서드를 사용하기 어려운 경우 등, 다른 메서드로 처리하기 애매한 경우 사용한다. |
PUT | - 리소스를 대체한다. - 리소스가 없는 경우 생성한다. - 클라이언트가 리소스 위치를 알고 URI를 지정하는 점이 POST와의 차이점이다. - PATCH와의 차이점은, 리소스를 일부만 변경하는 경우에도 바뀌지 않는 속성을 모두 보내야 한다는 점이다. |
PATCH | - 리소스를 부분적으로 변경한다. - PUT과 달리, 변경할 값만 보내면 된다. |
DELETE | 리소스를 삭제한다. |
HEAD | GET과 동일하지만 메시지 부분을 제외하고, 상태 줄과 헤더만 반환한다. |
OPTIONS | - 대상 리소스에 대한 통신 가능 옵션(메서드)을 설명한다. - 주로 CORS에서 사용한다. |
CONNECT | 대상 자원으로 식별되는 서버에 대한 터널을 설정한다. |
TRACE | 대상 리소스에 대한 경로를 따라 메시지 루프백 테스트를 수행한다. |
- 속성
종류 | 설명 |
Safe | 호출해도 리소스를 변경하지 않는다. |
Idempotent | 같은 요청을 여러 번 해도 결과가 똑같다. |
Cacheable | - |
2.2 리소스 간의 관계를 표현하는 방법
- 일반적인 소유 관계를 표현할 때 예시
GET /users/{userid}/devices
- 관계명이 애매하거나 구체적 표현이 필요할 때 예시
GET /users/{userid}/likes/devices
2.3 URI 설계 개념
종류 | 설명 |
문서(Document) | - 하나의 문서 혹은 객체라고 볼 수 있다. - 리소스라고 표현할 수 있으며 URI에 표현된다. - /members/100, /files/star.jpg 등이 예시이다. |
컬렉션(Collenction) | - 문서, 객체들의 집합이라고 볼 수 있다. - 복수를 의미한다. - 리소스라고 표현할 수 있으며 URI에 표현된다. - /members 등이 예시이다. |
스토어(Store) | - 클라이언트가 관리하는 자원 저장소를 의미한다. - 클라이언트가 리소스의 URI를 알고 관리한다. - /files 등이 예시이다. |
컨트롤러(Controller), 컨트롤 URI | - 문서, 컬렉션, 스토어로 해결하기 어려운 추가 프로세스를 실행한다. - 동사를 직접 사용한다. - /members/{id}/delete 등이 예시이다. |
2.4 자원을 표현하는 Collection과 Document
- 단수, 복수를 지켜 컬렉션과 도큐먼트를 사용하면 더욱 직관적인 REST API를 만들 수 있다.
// sports 컬렉션과 soccer 도큐먼트로 표현
http://restapi.example.com/sports/soccer
// sports, players 컬렉션과 soccer, 13 도큐먼트로 표현
http://restapi.example.com/sports/soccer/players/13
3. HTTP 응답 상태 코드
- 1xx(Informational): 요청이 수신되어 처리 중이다. 거의 사용하지 않는다.
- 2xx(Successful): 요청이 정상 처리되었다.
- 3xx(Redirection): 요청을 완료하려면 추가 행동이 필요하다.
- 4xx(Client Error): 클라이언트 오류, 잘못된 문법 등으로 서버가 요청을 수행할 수 없다.
- 5xx(Server Error): 서버 오류, 서버가 정상 요청을 처리하지 못한다.
종류 | 설명 |
200 OK | 클라이언트의 요청을 정상적으로 수행한다. |
201 Created | 클라이언트가 POST를 통한 어떠한 리소스 생성을 요청했을 때, 해당 리소스가 성공적으로 생성된다. |
202 Accepted | 요청이 접수되었으나 처리가 완료되지 않았다. |
204 No Content | 서버가 요청을 성공적으로 수행했지만, 응답 페이로드 본문에 보낼 데이터가 없다. |
300 Multiple Choices | 사용하지 않는다. |
301 Moved Permanently | - 클라이언트가 요청한 리소스에 대한 URI가 변경되었을 때 사용한다. - 응답 시 Location header에 변경된 URI를 적어야 한다. - 리다이렉트 시 요청 메서드가 GET으로 변한다. - 본문이 제거될 수도 있다. |
302 Found | - 리다이렉트 시 요청 메서드가 GET으로 변할 수 있다. - 본문이 제거될 수 있다. |
303 See Other | - 302와 기능은 같다. - 리다이렉트 시 요청 메서드가 GET으로 변경된다. |
304 Not Modified | - 캐시를 목적으로 사용한다. - 클라이언트에게 리소스가 수정되지 않았음을 알려준다. 따라서 클라이언트는 로컬 PC에 저장된 캐시를 재사용해서 리다이렉트 한다. - 로컬 캐시를 사용하기 때문에 응답에 메시지 바디를 포함하면 안된다. - 조건부 GET, HEAD 요청 시 사용한다. |
307 Temporary Redirect | - 302와 기능은 같다. - 리다이렉트 시 요청 메서드와 본문을 유지한다. |
308 Permanent Redirect | - 301과 기능은 같다. - 리다이렉트 시 요청 메서드와 본문을 유지한다. - 처음 POST를 보내면 리다이렉트도 POST를 유지한다. |
400 Bad Request | 요청 구문, 메시지 등에서 오류가 발생하여 클라이언트의 요청이 부적절한 경우 사용한다. |
401 Unauthorized | - 클라이언트가 인증되지 않은 상태에서 보호된 리소스를 요청했을 때 사용한다. - 로그인하지 않은 유저가 로그인 했을 때 요청 가능한 리소스를 요청했을 경우 등이 해당한다. - 응답에 WWW-Authenticate 헤더와 함께 인증 방법을 설명한다. |
403 Forbidden | - 유저 인증 상태와 관계 없이 응답하고 싶지 않은 리소스를 클라이언트가 요청했을 때 사용한다. - 403은 리소스가 존재한다는 것을 의미하기 때문에, 400이나 404 사용이 더 권고된다. - 주로 인증 자격은 있지만, 접근 권한이 불충분한 경우 사용한다. |
404 Not Found | - 요청 리소스가 서버에 없다. - 클라이언트가 권한이 부족한 리소스에 접근하는 경우에, 해당 리소스를 숨기고 싶을 때 사용한다. |
405 | 클라이언트가 요청한 리소스에서는 사용 불가능한 Method를 이용했을 경우 사용한다. |
500 Internal Server Error | - 서버에 문제가 있을 경우 사용한다. - 애매한 경우에는 500으로 처리하는 것이 일반적이다. |
503 Service Unavailable | - 서버가 일시적인 과부하 또는 예정된 작업으로 잠시 요청을 처리할 수 없을 때 사용한다. - Retry-After 헤더 필드로 얼마 뒤에 복구되는지 보낼 수 있다. |
3.1 Redirection
- 웹 브라우저는 3xx 응답의 결과에 Location 헤더가 있으면, Location 위치로 자동 이동한다.
종류 | 설명 |
영구 리다이렉션 | - 특정 리소스의 URI가 영구적으로 이동한다. - 원래의 URL을 사용하지 않는다. - 검색 엔진 등에서도 변경을 인지한다. - 301, 308이 해당한다. |
일시 리다이렉션 | - 리소스의 URI가 일시적으로 변경된다. - 검색 엔진 등에서 URL을 변경하면 안된다. - 주문 완료 후 주문 내역 화면으로 이동하는 것이 대표적인 예시이다. - 302, 303, 307이 해당한다. - 303, 307 사용이 권장되지만 현실적으로는 302가 가장 많이 사용되고 있다. 큰 문제는 없다. - PRG Pattern이 해당한다. |
특수 리다이렉션 | 결과 대신 캐시를 사용한다. |
3.2 PRG(Post/Redirect/Get) Pattern
- 일시 리다이렉션에 해당한다.
- POST로 주문 후에 새로고침으로 인한 중복 주문을 방지한다.
- POST로 주문 후에 주문 결과 화면을 GET 메서드로 리다이렉트 한다.
- 새로고침해도 결과 화면을 GET으로 조회한다. 중복 주문 대신에 결과 화면만 GET으로 다시 요청하는 것이다.
참고
- https://meetup.toast.com/posts/92
- https://devuna.tistory.com/77
- https://ko.wikipedia.org/wiki/HTTP
- https://sanghaklee.tistory.com/57
- https://restfulapi.net/resource-naming/
- 『모든 개발자를 위한 HTTP 웹 기본 지식』