Spring REST API - 기본편
Rest API 기본 개념
REST(REpresentational State Transfer) : 로이 필딩이 월드 와이드 웹(www)와 같은 하이퍼미디어 기반 분산 시스템을 구축하기 위해 만든 아키텍처입니다. REST API는 HTTP URI(Uniform Resource Identifier)를 통해 자원(Resource)을 명시하고, HTTP Method를 통해 해당 자원에 대한 CRUD 행위를 명시하여 제공하는 인터페이스입니다.
- API (Application Programming Interface)는 애플리케이션이 제공하는 기능을 다른 애플리케이션에서 제어할 수 있게 만든 인터페이스.
- URL(Uniform Resource Locator)은 자원이 실제로 존재하는 위치.
예) https://calendar.google.com/calendar
- URI(Uniform Resource Identifier)는 자원의 위치뿐만 아니라 자원에 대한 고유 식별자로서 URL을 의미를 포함.
예) https://calendar.google.com/calendar/u/0/r/month/2022/3/17
REST 특징
- Stateless(무상태성)을 가지며 세션 정보를 사용하지 않기 때문에 요청에 필요한 모든 정보가 포함되어야 합니다.
- HTTP 프로토콜 표준에서 사용하는 캐싱 구현이 가능합니다.
- Last-Modified태그나 E-Tag를 이용할 수 있습니다.
- HTTP Header에 cache-control 헤더를 이용하며 요청에 대한 캐시가 가능한지 명시하는 용도로 사용합니다.
- HTTP 표준 프로토콜에 따르는 모든 플랫폼에서 사용이 가능하기 때문에 범용성이 높습니다.
- REST API 메시지만 보고도 이를 쉽게 이해 할 수 있는 자체 표현 구조로 되어 있습니다.
- 백엔드(server)-프론트(client)의 역할을 명확하게 구분하여 개발할 수 있습니다.
- 데이터의 교환 형식은 JSON, XML 등이 있으며 주로 JSON을 사용합니다.
REST 구성
-
자원 - Resource URI
- 정보의 자원을 표현하는 고유한 URI를 사용하며 행위를 나타내는 동사적 표현은 제외합니다.
- 올바른 예) GET /api/v1/member/123
- 올바르지 않은 예) GET /api/v1/get/member/123, GET /api/v1/getMember
-
행위 - 자원에 대한 행위를 Http Method로 표현합니다.
- POST : 리소스 생성
- GET : 리소스 조회
- PUT : 리소스 수정 (해당 자원의 전체를 수정)
- DELETE : 리소스 삭제
- PATCH : 리소스 수정 (해당 자원의 일부를 수정)
-
표현
-
슬래시(/) 구분자는 계층 관계를 나타내는 데 사용합니다. 계층은 Collection과 Document로 나뉘는데 Document는 객체이고 Collection은 객체들의 집합이라고 생각하면 됩니다.
-
/api/v1/dept => 모든 부서 정보를 조회
-
/api/v1/dept/12 => 12번 부서 정보를 조회
-
/api/v1/dept/12/employee => 12번 부서의 모든 직원 정보를 조회
-
/api/v1/dept/12/employee/30 => 12번 부서의 30번 직원 정보를 조회
-
/api/v1/dept/12/employee?sex=male => 12번 부서의 남자 직원 정보를 조회
-
/api/v1/dept/12/employee?page=2&count=10&sort=rank_asc => 12번 부서의 직원을 10명씩 그룹핑하여 2번째 페이지를 조회
-
-
URI를 쉽게 읽고 해석하기 위해, 불가피하게 긴 URI경로를 사용하게 된다면 하이픈을 사용해 가독성을 높일 수 있습니다.
-
밑줄(_)은 URI에 사용하지 않고, 하이픈(-)을 사용하는 것이 좋습니다.
-
URI 경로는 소문자로 작성합니다.
-
파일 확장자는 URI에 포함시키지 않습니다.
-
리소스의 포맷 정보는 URI가 아닌 Header에 포함시킵니다.
- /api/v1/member/15/photo.jpg (x)
- /api/v1/member/15/photo Accept: image/jpg (o)
-
HATEOAS(Hypertext As Engine Of Application State)
마틴 파일러가 설명한 REST 모델링에서는 Rest API 모델을 0~3단계로 소개합니다.
-
Level 0: 단일 서비스 엔드포인트에 모든 요청
- Level 1: 개별 리소스 엔드 포인트에 요청
- Level 2: 개별 리소스 엔드 포인트 + 행위를 표현하는 HTTP Method 사용
- Level 3: 개별 리소스 엔드 포인트 + 행위를 표현하는 HTTP Method 사용 + HATEOAS 제공
HATEOAS(헤이티오스)는 리소스 엔드 포인트 요청 시 해당 리소스와 직접 관련된 리소스를 찾는데 필요한 링크 정보를 반환하는 하는 것을 말합니다.

HATEOAS 원칙을 모델링하는 방법을 정의하는 범용 표준은 없지만 Azure 아키텍처 디자인에서 표현 방식은 아래와 같습니다.
{
"orderID":3,
"productID":2,
"quantity":4,
"orderValue":16.60,
"links":[
{
"rel":"customer",
"href":"https://adventure-works.com/customers/3",
"action":"GET",
"types":["text/xml","application/json"]
},
{
"rel":"customer",
"href":"https://adventure-works.com/customers/3",
"action":"PUT",
"types":["application/x-www-form-urlencoded"]
},
{
"rel":"customer",
"href":"https://adventure-works.com/customers/3",
"action":"DELETE",
"types":[]
},
{
"rel":"self",
"href":"https://adventure-works.com/orders/3",
"action":"GET",
"types":["text/xml","application/json"]
},
{
"rel":"self",
"href":"https://adventure-works.com/orders/3",
"action":"PUT",
"types":["application/x-www-form-urlencoded"]
},
{
"rel":"self",
"href":"https://adventure-works.com/orders/3",
"action":"DELETE",
"types":[]
}]
}
HAL이란 Hypertext Application Language의 약자로 JSON 또는 XML 코드 내의 외부 리소스에 대한 링크와 같은 하이퍼 미디어를 정의하기 위한 표준 규칙입니다.
응답의 Content-type은 application/hal+json을 사용하고, _links 속성은 클라이언트가 수행할 수 있는 작업을 포함한다.
_links의 속성 값들은 다음과 같다.
- rel : 리소스의 상태 관계를 나타내며 self의 경우 현재 url 자신을 지칭하는 예약어입니다.
- href: 리소스를 나타내는 URI입니다.
- action: 리소스 요청시 필요한 http method입니다.
- types: 요청
장점
- 서버의 응답 메시지는 단순하기 때문에 클라이언트에서 상태 전이를 할 때 _links 정보가 있으면 손쉽게 처리할 수 있다.
- 서버의 엔드 포인트 URL을 변경해도 클라이언트는 제공되는 링크를 통해서 접근할 수 있기 때문에 URI를 하드코딩할 필요가 없습니다.
단점
- 서버 측과 클라이언트 모두 개발의 복잡성이 증가할 수 있습니다.
- Level 2까지만 구현해도 충분히 개발 가능하고 Level3(HATEOAS)를 구현하는데 드는 비용대비 이점이 적습니다. API 응답을 통해 전달 받는 _links 정보는 일부분이기 때문에 클라이언트는 수행해야할 작업을 하기 위해 API 문서를 확인해야 되고 그에 맞는 작업이 필요하기 때문입니다.
결론
- 프로젝트의 일정이 여유가 있고 팀원들이 의욕을 보인다면 적용해보고 아니라면 적용하지 않으면 됩니다.
응답코드
-
2xx: 클라이언트 요청이 성공적으로 수행 됨.
-
200 : GET, PUT, PATCH 메서드로 리소스 정보 요청을 정상처리 함을 나타내는 응답코드.
-
201 : POST 메서드로 리소스 생성 요청을 정상처리 함을 나타내는 응답코드.
-
204 : DELETE 메서드로 리소스 삭제 요청을 정상처리 함을 나타내는 응답코드.
-
-
3xx: URI 변경
- 301 : 클라이언트가 요청한 리소스에 대한 URI가 영구 변경
- 302 : 클라이언트가 요청한 리소스에 대한 URI가 임시 변경
-
4xx: 클라이언트의 잘못된 요청.
-
400 : 클라이언트 요청이 부적절할 때 사용 (부적절한 이유를 응답 Body에 넣어줘야 함)
HTTP/1.1 400 Bad Request { "message": "`gil-logging` must be required, but no parameter requested" }
-
401 : 클라이언트가 인증되지 않은 상태에서 보호된 리소스를 요청할 때 사용
-
403 : 클라이언트가 인증상태와 무관하게 응답하고 싶지 않은 리소스를 요청할 때 사용
-
404 : 클라이언트가 요청한 리소스가 존재하지 않을 때 사용
-
405 : 클라이언트가 불가능한 메소드를 사용했을 때
-
409 : Conflict, 해당 요청 처리가 로직상 수행 불가능하거나 모순이 발생한 경우
-
429: Dos, Brute-Force-Attck등 비정상적인 많은 요청의 경우, 429 응답 후 해당 IP의 요청 수를 제한
HTTP/1.1 429 Too Many Requests Retry-After: 3600
-
-
5xx: 서버쪽 오류
- 500 : request는 유효하지만 서버에 문제가 발생.
- 503 : 서버가 다운되거나 request를 처리할 수 없음.
-
다른 서비스에서 사용하는 응답코드
-
Google GData : 200 201 304 400 401 403 404 409 410 500
-
Netflix : 200 201 304 400 401 403 404 412 500
-
버전 관리
api가 변경되거나 삭제되면 기존에 api를 호출하던 콜러 서비스에서 오류가 발생할 수 있으므로 기존 버전을 유지하는 것이 좋습니다.
- URI에 버전 명시 : /api/v2/member
- queryparameter에 버전 명시 : /api/member?version=2
- HTTP Header에 버전 명시: Custom-Header: api-version=2
참조
댓글남기기