[스프링부트 핵심 가이드] 책을 읽고 정리한 내용입니다.
아마 REST API는 대중적으로 가장 유명하고 많이 사용되는 애플리케이션 인터페이스이다. REST API의 REST가 무엇을 의미하고 어떤 형식과 규칙이 있는지 알아보자.
🌐 REST란?
REST란 'Representational State Transfer'의 약자로, 월드 와이드 웹(WWW)과 같은 분산 하이퍼미디어 시스템 아키텍처의 한 형식이다.
주고받는 자원(Resource)에 이름을 규정하고 URI에 명시해 HTTP 메서드(GET, POST, PUT, DELETE)를 통해 해당 자원의 상태를 주고받는 것을 의미한다.
즉, REST는 서버와 클라이언트의 통신 방식 중 한 가지이며, 위 문장을 해석해 보면 HTTP URL를 통해 자원을 명시하고 HTTP Method를 통해 자원을 교환하는 것을 의미한다.
🌐 REST의 특징
REST는 다음과 같은 특징을 갖는다.
유니폼 인터페이스
유니폼 인터페이스란 '일관된 인터페이스'를 의미한다. 즉, REST 서버는 HTTP 표준 전송 규약을 따르기 때문 같은 언어 프로그래밍이 아니더라도 HTTP 프로토콜을 따르는 다른 플랫폼에서 일관되게 호환하여 사용할 수 있다. (플랫폼 및 기술에 종속되지 않는다.)
무상태성(Stateless)
REST '무상태성(stateless)'이라는 특징을 가진다. 무상태성이란 서버에 상태 정보를 따로 보관하거나 관리하지 않는다는 의미이다. 서버는 클라이언트가 보낸 요청에 대한 세션이나 쿠키 정보를 따로 보관하지 않는다. 그렇기 때문에 한 클라이언트가 여러 요청을 보내든 각각 하나씩 요청을 보내든 개별적으로 처리한다. 이렇게 구성된 서비스는 서버가 불필요한 정보를 관리하지 않기 때문에 비즈니스 로직의 자유도가 높고 설계가 단순하다.
캐시 가능성(Cacheable)
REST는 HTTP 표준을 그대로 사용하므로 HTTP의 캐싱 기능을 적용할 수 있다. 이 기능을 활용하기 위해선 응답과 요청이 모두 캐싱 가능한지(Cacheable) 명시가 필요하며, 캐싱이 가능한 경우 클라이언트에서 캐시에 저장해 두고 같은 요청이 왔을 때 해당 데이터를 가져다 사용한다. 이 기능을 사용하면 서버의 트랙잭션 부하가 줄어 효율적이며 사용자 입장에서 성능이 개선된다.
레이어 시스템
REST 서버는 네트워크 상의 여러 계층으로 구성될 수 있다.(로드밸런싱, 보안 요소, 캐시 등) 그러나 서버의 복잡도와 관계없이 클라이언트는 서버와 연결되는 포인트만 알면 된다.
즉, 클라이언트는 서버의 구성과 상관없이 REST API 서버로 요청하면 된다는 이야기이다.
클라이언트-서버 아키텍처
REST 서버는 API를 제공하고 클라이언트는 사용자 정보를 관리하는 구조로 분리해 설계한다. 이 구조는 서로에 대한 의존성을 낮추는 기능을 한다.
쉽게 이야기하면, 클라이언트는 서버에게 자료나 데이터를 요청하며 서버는 클라이언트의 요청에 응답하여 원하는 데이터를 제공해 준다.
이런 구조를 갖춤으로 클라이언트와 서버는 독립적으로 분리되며 서로에 대한 의존성을 낮춘다.
🌐 REST API란?
먼저 API는 'Application Programming Interface'의 약자로, 애플리케이션에서 제공하는 인터페이스를 의미한다. API를 통해 서버 또는 프로그램 사이를 연결할 수 있다.
즉, REST API는 REST아키텍처를 따르는 시스템/애플리케이션 인터페이스라고 정의할 수 있다. REST 아키텍처를 구현하는 웹 서비스를 'RESTful 하다'라고 표현한다.
🌐 REST API의 특징
REST 기반으로 시스템을 분산해 확정성과 재사용성을 높여 유지보수 및 운영을 편리하게 할 수 있다.
HTTP 표준을 따르고 있어 여러 프로그래밍 언어로 구현할 수 있다.
🌐 REST API의 설계 규칙
REST API 설계 필요한 규칙이다.
URI의 마지막에는 '/'를 포함하지 않는다.
- 경로를 표현함에 있어 슬래시는 계층을 구분하기 위해 사용된다.
- 옳은 예) http://localhost.com/product
- 잘못된 예) http://localhost.com/product/
언더바(_)는 사용하지 않는다. 대신 하이픈(-)을 이용한다.
- 옳은 예) http://localhost.com/product-company
- 잘못된 예) http://localhost.com/product_company
자원에 대한 행위는 HTTP 메서드로 표현한다.
- URI에 HTTP Method가 들어가면 안 된다.
- GET /members/delete/1 -> DELETE /members/1
- URI에 행위에 대한 동사 표현이 들어가면 안 된다. 즉, CRUD 기능을 나타내는 것은 URI에 사용하지 않는다.
- GET /members/show/1 -> GET /members/1
- GET /members/insert -> POST /members
- URI 중 변하는 부분은 유일한 값으로 대체한다. 예를 들면, id는 하나의 특정 resource를 나타내는 고유값이다.
- student를 생성하는 경로: POST /students
- id=12인 student를 삭제하는 경로: DELETE /students/12
동사대신 명사를 사용한다.
- URL에선 명사를 사용하고 동사의 사용을 피한다.
- 일반적으로 복수형으로 표현한다.
URI는 소문자로 작성해야 한다.
- URI 리소스 경로에는 대문자를 피하는 것이 좋다.
- 일부 웹 서버의 운영체제는 리소스 경로 부분의 대소문자를 다른 문자로 인식하지 때문이다. 이러한 이유로 RFC3986은 URI 문법 형식을 정의하고 있는데, 호스트의 구성요소를 제외하고 URI의 대소문자를 구분해서 정의하고 있다.
파일의 확장자는 URI에 포함하지 않는다.
- 파일 확장자가 경로에 포함되면 안 된다.
- 확장자의 처리는 Content-Type, Accept 헤더 등을 사용하여 표현하는 것이 좋다.
HTTP 메서드란?
Rest API에서 사용되는 HTTP 메서드
GET
서버에 세 자원을 요청하는 데 사용한다.
POST
서버에 자원을 생성할 때 사용한다.
PUT
서버에 자원을 생성 및 업데이트하기 위해 사용한다. 주로 자원을 수정할 때 사용한다.
DELETE
서버의 자원을 삭제하기 위해 사용한다.
🌐 RESTful한 API Endpoint 설계 예제
예시로, 'accounts'라는 리소스에 대한 RESTful 한 API 엔드포인트를 설계해 보자.
- GET /api/v1/accounts : 계좌 정보 내역 조회
- GET /api/v1/accounts/{accountsNumber} : 특정 계좌 정보 조회
- GET /api/v1/accounts/{accountsNumber}/detail : 특정 계좌 상세 정보 조회
- POST /api/v1/transfer : 계좌 이체
- POST /api/v1/customers : 고객 가입
- DELETE /api/v1/accounts/{accountsNumber} : 계좌 삭제
여기서 주의 깊게 볼 것은 특정 계좌 상세 정보 조회의 URL이다. 연관된 리소스(자원) 간의 관계를 나타낼 때는 계층구조로 나타낼 수 있다. 예를 들어 특정 계좌 상세 정보 조회를 나타내면 ' /accounts/{accountsNumber}/detail'와 같은 형식을 따르게 된다. 상위 계층자인 accounts와 그의 해당하는 식별자를 같이 쓰고 그다음 하위 속성의 해당하는 detail를 추가하는 구조이다.
민약 이러한 규칙을 사용하지 않으면 어떻게 될까?
특정 계좌 상세 정보 조회를 ' /accounts/detail/{accountsNumber} ' 이런 식의 표현을 사용하게 되면 {accountNumber}가 accounts의 식별자인지 detail의 식별자인지 한 번에 파악하기가 힘들게 된다.
또 하나 '/api/v1/transfer'를 살펴보면 transfer는 동사적 표현이다. REST API에서 동사를 사용하지 말라는 표현은 HTTP 메서드를 표현(get-user 같은)하지 말라는 것이지 자원을 컨트롤하는 의미에서는 예외적으로 동사적 표현도 허용한다.
RESTful API 설계하는 것은 정답은 없다. 하지만 어느 정도 일관된 설계를 하는 것이 API를 사용하는 클라이언트 개발자에게 직관적이고 예측 가능한 환경을 제공하므로, 위에 나온 규칙을 활용해 설계를 진행하도록 하자.
'Framework > Spring' 카테고리의 다른 글
[Spring] POST, PUT, DELETE API (0) | 2023.10.11 |
---|---|
[Spring] GET API를 구현하는 다양한 방법 (0) | 2023.10.06 |
[Spring] 레이어드 아키텍처와 스프링의 레이어드 아키텍처 (0) | 2023.10.05 |
[Spring] 스프링 부트의 동작 방식 (0) | 2023.10.05 |
[Spring] 스프링 프레임워크 vs 스프링 부트 (0) | 2023.10.04 |