본문 바로가기

Network & Web

RESTful API는 어떻게 만들 수 있을까?

RESTful API를 설명하기 전에 REST의 개념과 속성에 대해 학습하고 넘어가야한다.

REST란?

Representational State Transfer의 약자로, 현재 웹의 아키텍처 스타일이다. 따라서 어떠한 프로토콜이나 표준이 아니라 아키텍처 원칙들이 모여있는 말 그대로 아키텍처 스타일이다. 아키텍처 스타일은 소프트웨어를 설계할 때 이 아키텍처 스타일에 해당하는 규약들을 적용해가며 설계하는 것이다. REST는 로이 필딩이 박사학위 논문으로 정의하였다고 한다.

 

REST의 구성

1. 자원 (Resource)

REST에서 가장 중요한 단어이다. REST에서는 각각의 자원을 이름을 붙여 구분하고 이 이름은 URI로 표현한다. 자원을 URI를 붙여 간단히 가리킬 수 있다.

예를 들어, 어떠한 게시판의 1번 게시물을 이름으로 붙이고 싶다면 '/post/1'로 표현할 수 있다.

말 그대로 해당 자원을 표현하기 위한 이름이다. 여기서 1번의 게시물을 가져오고 싶어 URI를 '게시물을 가져오다'의 뜻인 '/getPost/1' 이런 식으로 동사를 붙여 가져오면 안된다. 사람 이름이 명사로 표현되듯이 자원의 이름도 명사로 표현한다.

2. 행위 (Verb)

자원을 명사로 표현해야 한다면 특정 자원을 가져오거나 혹은 자원을 등록할 때 분명 동사로 표현을 해야할 것이다. 이 때 REST에서는 HTTP 메서드를 통해 표현한다. 

예를 들면, 게시물 1번을 가져오다의 표현을 요청메시지에서 표현한다면  'GET /post/1 HTTP/1.1' 가 될 수 있다.

등록한다면 'POST /post/1 HTTP/1.1'이 된다. HTTP는 프로토콜이고 1.1은 버전이다

3. 표현 (Representation)

클라이언트가 요청을 보내고 서버는 응답을 한다. 여기서 데이터를 주고받는데 이 데이터를 표현하는 형태를 말한다.

REST에서는 여러 형태로 표현할 수 있는데 JSON, XML, TEXT, RSS 등이 있다. 주로 JSON으로 많이 표현한다.

 

 

여기까지 구성요소에 대해서 살펴보았다. 이제 REST 아키텍처에 적용되는 6가지의 제한 조건에 대해 알아보자.

 

6가지의 제한 조건

클라이언트/서버

애플리케이션을 개발해본 경험이 있다면 매우 친숙하게 다가오는 성질일 것이다. 클라이언트가 요청을 보내면 서버가 응답을 한다. 단일 컴퓨터상으로 모든 것을 처리하는 것이 아니라 클라이언트와 서버로 분리가 되어 자기의 역할에만 집중할 수 있다. 

이렇게 되면 장점은 다양한 형태의 클라이언트가 서버에 접근할 수 있고, 서버도 복수의 서버로 운영하여 클라이언트에게 서비스를 제공해주는 등으로 확장해나갈 수 있다.

스테이트리스(Stateless) 서버

딱 보자마자 의미가 와닿았겠지만 서버가 클라이언트의 상태를 기억하고 관리하지 않는다. 클라이언트는 요청할 때 서버가 Request 메시지만 보고도 이해할 수 있도록 필요한 데이터를 포함해서 보내야 한다. 서버가 클라이언트의 상태를 저장하고 있지 않기 때문에 구현이 간략화되어 부하를 예방할 수 있다. 서버는 클라이언트의 요청에 대한 응답을 하면 바로 자원을 해제한다. 

 

하지만 단점은 존재한다. 이 아키텍처 스타일을 적용하게 되면 서버가 클라이언트 상태를 기억하고 있지 않기 때문에 같은 데이터를 반복적으로 요청할 경우 네트워크 성능이 좋지 않은 효과를 보일 수 있다. 이럴 경우 stateless의 반대말인 Stateful 서버를 선택하는 경우도 많다. Stateless 단점을 보완하기 위해 선택하는데 대신 Stateful하면 안정성이 떨어질 수 있다. 

캐시 (Cache)

캐시는 서버에서 가져온 리소스를 클라이언트가 돌려쓰는 방식을 말한다. 이 캐시의 장점은 네트워크 통신량을 줄일 수 있어서 처리시간을 단축시키고, 효율적으로 처리가 가능하다. 대신 오래된 캐시는 신뢰할 수 없으므로 유의해서 사용해야한다.

 

여기서 궁금한 점이 있다.

방금 서버가 클라이언트 정보를 보관하지 않는다고 했는데 왜 캐시로 다시 보관한다고 하지?

여기서는 차이가 있다. Stateless 서버는 클라이언트와 서버가 통신한 History나 정보를 보관하지 않는다. 따라서 클라이언트는 Request를 보낼 때마다 요청 횟수와 상관없이 처음 요청을 보내는 것처럼 필요한 데이터를 포함하여 보내고 서버 또한 처음 요청에 대한 처리를 하듯 수행한다.

Cache는 서버가 요청을 많이 받은 리소스의 복사본을 저장한다. 캐싱 전략은 Stateless와 Stateful 모두 사용할 수 있다. 

유니폼 인터페이스

REST 구성요소를 설명할 때 소개했지만 리소스를 조작할 때 통일된 인터페이스를 수행하는 것을 말한다. 

 

1. 리소스가 URI로 식별된다.

이 말은 위의 구성요소에서 정리했던 내용이므로 생략한다.

 

2. 표현을 통해 리소스를 조작한다.

리소스를 요청할 때 서버는 리소스를 표현하여 응답한다. 이 표현은 클라이언트가 이해하고 조작할 수 있는 형식으로 리소스의 충분한 정보를 담아낸다.

 

예를 들면 어떤 주문에 대한 응답메시지를 text 형식으로 표현했다면 아래처럼 메타데이터로 명시해줘야한다.

GET /orders/12345

Accept: text/plain

 

또는 json 형식으로 표현했다면 아래처럼 표현해야한다.
GET /orders/12345

Accept: application/json

 

3. 자기 기술적인 메시지 (self-descriptive message)

응답메시지에는 클라이언트가 리소스를 가지고 어떤 일을 수행할 때 필요한 모든 데이터가 포함되어 있어야한다.

 

예를 들면 response body에 데이터가 존재한다면 body에 있는 데이터를 문서로 작성하여 해당 자원에 대해 명시해주는 식으로 구현한다.

 

4. 하이퍼링크를 통한 웹페이지 전이 (HATEOAS)

클라이언트가 리소스에 엑세스한 후에 하이퍼링크를 통해 현재 수행가능한 모든 작업을 찾을 수 있어야한다. 다시 풀어얘기하면 만약 클라이언트가 관련된 리소스에 접근하기를 원한다면 응답 데이터에 링크가 포함되어 있어야한다.

계층화 시스템

클라이언트가 볼 수 없고, 시스템을 계층 구조로 체계화한 것을 말한다. 예를 들면, 부하를 분산시키기 위해 서버와 클라이언트 간의 로드밸런서를 설치하거나 혹은 프록시를 설치해 엑세스를 제어할 수 있다. 하지만 클라이언트는 이러한 사정을 알 필요없이 똑같이 요청하고 응답을 받는다.

코드 온 디맨드 (옵션)

서버에 코드를 요청하면 다운받아 클라이언트에서 실행시킬 수 있다. Javascript나 Java 애플릿이 여기에 해당된다.

코드 온 디맨드의 장점은 클라이언트를 차후에 확장할 수 있는 것이다. 단점은 프로토콜의 가시성을 저하시킨다는 점이다. 클라이언트가 코드를 실행시켜버리면 통신의 의미가 모호해진다는 점이다.

 

 

그럼 RESTful API는 어떻게 만들 수 있을까?

말 그대로 REST 제한조건들을 잘 지키면 된다.

여기서부터는 그냥 내 생각이다. 애플리케이션을 개발할 때 보다 RESTful 한 API를 만들기 위해 어떤 것들을 신경써야할까? 

 

첫째, URI를 만들 때 주의해야한다. 

해당 URI를 리소스의 명칭으로서 사용하고 있는지 특정 행위를 위한 이름으로 정한 것이 아닌지 말이다.

 

둘째, HTTP 메소드를 적절하게 사용해야한다.

resource /post/1 

GET 리소스 조회

POST 리소스 생성

PUT 리소스 수정

DELETE 리소스 삭제

이처럼 통일한 행위의 표현으로 사용하자.

 

셋째, body의 데이터를 이해시켜주는 메타데이터와 status를 적절하게 설정하여 응답하자.

리소스를 생성하면 created(URI), 수정하면 ok 또는 no_content , 권한이 없는 리소를 요청하면 forbidden, 

이처럼 적절한 status로 응답해준다. 또한 데이터의 형식 JSON 형식이라면 꼭 설정해서 넘기자.

 

넷째, API의 문서를 작성하자.

요즘은 spring의 REST Docs 이나 swagger 등을 사용하여 자동으로 만들어주는 편리한 것들이 많이 있다.

body의 데이터를 보고 이해할 수 있는 문서를 명시화하는 것에 습관을 들이자.

 

다섯째, 하이퍼링크를 통한 웹 페이지 전이를 실행하자.

응답메시지에 보내는 데이터 중 관련된 리소스가 있다면 URI를 추가하여 응답하자. spring boot의 경우 spring-boot-hateos가 있어 조금 더 편리하게 구현할 수 있다고 한다. 

 

 

 

 

 


학습 출처