처음 해보는 Spring Framework 미션. 나는 요구 사항을 모두 만족시키고 리뷰 요청을 보냈다. 그리고 아래와 같은 리뷰를 받았다.
스프링 미션을 진행하면서 URI에대한 고민을 잠깐 했지만, 현재 고민해야 될 내용이 아니라고 생각하고 넘어갔다. 하지만 내 생각은 틀렸다. 이번 기회를 통해 REST API에 대해 좀 공부해보고 그 내용을 정리해본다.
REST란
월드 와이드 웹과 같은 신뢰성이 있고 확장성이 있는 분산 시스템을 구축하기위한 아키텍쳐 디자인 제약의 모음이다. 여기서 ‘신뢰성’은 ‘어떤 컴포넌트에 장애가 발생하더라도 분산 시스템이 서비스를 제공할 수 있는 능력’정도로 이해했다. 그리고 ‘확장성’은 ‘작업을 처리할 수 있는 양이 지속적으로 발전될 수 있는 능력’이라고 이해했다. REST를 사용하면 클라이언트와 서버를 분리할 수 있기때문에, 확장성이 높고, 유연하게 사용할 수 있다. 여기서 REST의 제약들을 준수한 시스템을 RESTful하다고 일컫는다. 여기서 REST는 표준이 아니라 하나의 아키텍처 스타일이라는 것에 유의해야된다.
REST의 6가지 제약 조건
- 클라이언트-서버 구조: 사용자 인터페이스 문제와 데이터 저장 문제를 분리한다. 이를 통해 여러 플랫폼에서 사용자 인터페이스를 이식할 수 있도록 개선한다. 또한 서버 컴포넌트들을 단순화 시킬 수있다.
- 무상태(Stateless): 클라이언트에서 서버로 보내는 요청에 이해에 필요한 모든 정보를 포함해야된다. 서버는 클라이언트의 상태를 저장하면 안되며, 세션 상태는 전적으로 클라이언트에서 유지해야된다. 서버가 상태를 관리할 필요가 없기 때문에 구현이 더 단순화된다.
- 캐시: 서버의 응답 내에 있는 데이터를 캐싱할 수 있다. 응답을 캐싱하게되면 클라이언트의 동등한 요청에 데이터를 재사용할 수 있게된다. 이 캐시를 통해 일부 통신을 일부 제거할 수 있게되어 성능을 향상시킬 수 있다.
- 인터페이스 일관성: 클라이언트에 의존하지 않고, 표준화 된 인터페이스를 갖도록한다.
- 계층화(Layered System): 클라이언트나 서버에 미들웨어 컴포넌트를 추가할 수 있도록 해야된다. 하지만 Client-Server 사이에서는 그 컴포넌트가 추가되었는지, 다른 서비스와 추가로 통신하는지에는 관심이 없다.
- Code-On-Demand: 선택적인 제약 조건이다. 서버로부터 받은 프로그램을 클라이언트에서 실행할 수 있어야된다.
REST의 구현
REST를 구현하는 대표적인 사례가 HTTP를 활용한 방법이다. 웹 환경 통신의 대부분이 HTTP를 사용하기 때문에 REST는 무조건 HTTP로 구현된다고 생각한다. 사실 REST는 WAP, WebRTC, MQTT 등의 다른 프로토콜로도 구현이 가능하다. 아래는 HTTP를 이용하여 REST를 구현할 때 적용되는 규칙들이다.
HTTP 메서드를 사용하여 요청의 의미를 가지게 하기
HTTP 메서드에서 주로 사용하는 것은 아래 5가지가 있다. 이 메서드롤 리소스에 대응하는 작업의 의미를 가지게한다.
HTTP 메서드 | CURD | 전체 컬렉션(e.g. /customers) | 특정 항목(e.g. /customers/{id}) |
---|---|---|---|
POST | Creat | 201(Created): ‘Location’ 헤더에 생성된 항목의 ID를 포함하여 링크를 남긴다 (e.g /customers/{id}) | 404(Not Found), 만약 이미 존재한다면 409(Conflict) |
GET | Read | 200(OK): customers의 리스트. 목록이 크다면 pagination, sort, filter을 사용할 수 있다 | 200(OK), 만약 ID가 없거나 유효하지 않은 경우 404(Not Found) |
PUT | Update/Replace | 컬렉션의 모든 리소스를 교체하려는 것이 아니면 405(Method Not Allowed) | 200(OK), 만약 ID가 없거나 유효하지 않은 경우 404(Not Found) |
PATCH | Update/Modify | 컬렉션 자체를 수정하려는 것이 아니면 405(Method Not Allowed) | 200(OK) 또는 204(No Content), 만약 ID가 없거나 유효하지 않은 경우 404(Not Found) |
DELETE | Delete | 컬렉션 전체를 삭제하려는 경우가 아니라면 405(Method Not Allowed) | 200(OK) 또는 204(No Content), 만약 ID가 없거나 유효하지 않은 경우 404(Not Found) |
-
PUT과 PATCH의 차이
처음 Update를 위한 메서드가 2개라 혼란스러울 수 있다. 이를 이해하기 위해서는 멱등성이라는 개념을 알아야된다. 멱등성은 동일한 요청을 한 번 보내는 것과 여러 번 연속으로 보내는 것이 같은 효과를 지니는지를 나타내는 성질이다. 대표적으로
GET
,PUT
,DELETE
가 멱등성을 가지고,POST
,PATCH
는 멱등성을 가지지 않는다.PUT
의 경우에는 요청의 body 내용을 그대로 리소스를 교체하게 되지만,PATCH
는 사이드 이펙트가 있는 업데이트다.
적절한 리소스 이름 제공하기
적절한 리소스 이름은 API의 이해도를 높일 수 있다. 리소스는 URI 이름을 통해 계층적으로 표시되므로 클라이언트에게 친숙하고 이해하기 쉬운 형태여야된다. 여기서 리소스란 무엇일까? REST가 처음 소개된 로이 필딩의 논문 “Architectural Styles and the Design of Network-based Software Architectures“에 따르면 정보의 추상화다. 문서, 이미지, 임의의 서비스, DB 테이블의 한 행 등 하이퍼 텍스트의 참조 대상이 될 수 있는 모든 정보를 추상화한 것에 해당한다. 아래는 URI 경로(리소스 이름) 디자인에 대한 몇 가지 규칙이다.
- 쿼리 문자열 대신 URI에 식별자를 사용해라.
- 좋음 예: /users/12345
- 나쁜 예: /api?type=users&id=23
- URL의 계층적 특성을 활용해서 구조를 나타낸다.
- 데이터 관점이 아니라 소비자 관점의 디자인을 해야된다.
- 리소스의 이름은 명사 여야한다. 요청의 행동에 대한 부분은 HTTP 메서드로 표현한다.
- 컬렉션을 나타낼 때는 복수 형으로 나타내야된다.
- 좋은 예: /customers/33245/orders/8769/lineitems/1
- 나쁜 예: /customer/33245/order/8769/lineitem/1
- URL에 컬렉션의 표현을 포함하지 않는다(예: customer-list)
- URL 세그먼트에 소문자를 사용하고 하이픈(‘-‘)으로 단어를 구분한다. 일부 서버에서는 대소 문자를 무시하기 때문이다.
- 의미가 있는 세그먼트만 남겨서 URL을 최대한 짧게 남긴다.
참고 자료
https://developer.mozilla.org/ko/docs/Glossary/REST
https://d2.naver.com/helloworld/206816
https://sanghaklee.tistory.com/61
댓글남기기