REST API란?

hjkim·2022년 4월 21일
3
post-custom-banner

REST API는 개발자라면 개발하며 한 번쯤은 들어봤을 용어이다. 필자 또한 REST API를 수도 없이 들어보았고, REST API에 대해 '알고 있다'고 착각했다. 정작 누군가 'REST API가 무엇이냐? RESTful한 API를 설계해보라' 라고 했을 때 어떻게 해야 할 지 난감했다. 하여 이번 포스팅을 통해 REST란 무엇인지, RESTful한 API는 어떻게 구현될 수 있는지 정리해보고자 한다.


1. REST의 사전적 의미

REST는 REpresentational State Transfer의 약자이다. 자원을 이름으로 구분하여 해당 자원의 상태 정보를 주고받는 모든 것을 의미한다. 즉, 자원(resource)의 표현(representation)에 의한 상태 전달을 의미한다.

RESTful API는 REST 아키텍처의 제약 조건을 준수하는 Application Programming Interface이다. 웹의 창시자 중 한 사람인 로이 필딩(Roy Fielding)의 논문에 의해 소개되었다. 현재의 아키텍쳐가 웹의 본래 설계의 우수성을 많이 사용하고 있지 못하고 있다 판단하여 웹의 장점을 최대한 활용할 수 있는 네트워크 기반의 아키텍쳐를 소개했는데 그것이 바로 REpresentational State Transfer, REST이다.

그렇다면 다음은 어떤 제약 조건을 준수해야 REST 할 수 있는지에 대해 확인해보도록 한다.


2. REST 아키텍처에 적용되는 6가지 제한 조건

1) 클라이언트/서버 구조(Client-Server)

아키텍처를 단순화시키고 작은 단위로 분리(decouple)함으로써 Client-Server의 각 파트가 독립적으로 개선될 수 있도록 해준다. 즉, 자원이 있는 쪽인 Server와 자원을 요청하는 Client로 나누어져 있어야 한다. Server에서는 비즈니스 로직 처리 및 저장을 책임지며 API를 제공한다. Client에서는 요청한 자원을 화면에 나타내는 역할을 책임진다.

Client와 Server를 분리함으로써 서로간의 의존성이 줄어든다는 장점이 존재한다.

2) 무상태(Stateless)

각 요청 간 클라이언트의 context가 서버에 저장되어서는 안 된다. 세션과 쿠키와 같은 context 정보를 고려하지 않아야 한다. Server는 각각의 요청을 완전히 별개의 것으로 인식하고 처리한다. 이전 요청이 다음 요청의 처리에 연관되어서는 안된다.

Server의 처리 방식에 일관성을 부여하고 부담이 줄어들며, 서비스의 자유도가 높아진다는 장점이 존재한다.

3) 캐시 처리 가능(Cacheable)

클라이언트는 응답을 캐싱할 수 있어야 한다. HTTP 프로토콜이 가진 강력한 특징 중 하나인 캐싱 기능을 적용할 수 있다.

대량의 요청을 효율적으로 처리할 수 있고 캐시 사용을 통해 응답시간이 빨라진다는 장점이 존재한다. Server 트랜잭션이 발생하지 않아 전체 응답시간, 성능, 서버의 자원 이용률을 향상시킬 수 있다.

4) 인터페이스 일관성(Uniform Interface)

일관적인 인터페이스로 분리되어야 한다. 해당 부분은 아래에서 추가 설명하도록 한다.

5) 계층화(Layered System)

클라이언트는 보통 대상 서버에 직접 연결되었는지, 중간 서버를 통해 연결되었는지 알 수 없다. 중간 서버는 로드 밸런싱 기능이나 공유 캐시 기능을 제공함으로써 시스템 규모 확장성을 향상시키는 데 유용하다.

6) Code-on-Demand (Optional)

서버로부터 스크립트를 받아 클라이언트에서 실행한다. 반드시 충족할 필요는 없다.

대체로 개발자들이 'Restful한 API이다'라고 설계한 api들은 위의 조건들을 지키고 있다. HTTP만 잘 활용하면 Client-Server, Stateless, Cacheable, Layered System을 다 지킬 수 있기 때문이다. 하지만 대부분의 Restful하다고 주장하는 API들이 Restful하지 않은 이유는 인터페이스 일관성(Uniform Interface) 때문이다.

다음은 인터페이스 일관성(Uniform Interface)이 보장되기 위한 요건들에 대해 살펴본다.


3. Uniform Interface 제약조건

1) 자원의 식별(Identification of resources)

요청 내에 기술된 개별 자원을 식별할 수 있어야 한다. 말 그대로 URI를 통해 리소스가 식별이 되어야 한다.

2) 메시지를 통한 리소스의 조작(Manipulation of resources through representations)

클라이언트가 어떤 자원을 지칭하는 메시지와 특정 메타데이터만 가지고 있다면 이것으로 서버 상의 해당 자원을 변경/삭제할 수 있는 충분한 정보를 가지고 있는 것이다. 즉, 자원을 변경/삭제하고자 할 때 http 메시지에 해당 표현을 전송해야 한다. 보통 http method를 통해 전송한다.

3) 자기서술적 메시지(Self-descriptive messages)

각 메시지는 자신을 어떻게 처리해야 하는지에 대한 충분한 정보를 포함해야 한다. 보통 이 조건 때문에 우리나라에서 사용되는 대부분의 웹 API는 Restful 할 수 없다.

아래와 같은 메시지가 있다.

HTTP/1.1 200 OK
Content-Type: application/json
[ { "op": "remove", "path": "/a/b/c" } ]

위 메시지는 self-descriptive 한가? 사용한 프로토콜, 응답 성공 여부를 나타낸 http status code, 응답 본문을 해석할 수 있도록 돕는 Content-Type을 전부 명시하고 있다. 해당 응답은 self-descriptive 한가, 즉 해당 응답만 보고 무엇에 대한 응답인지 알 수 있는가? 언뜻 보면 self-descriptive 하다고 볼 수 있으나 self-descriptive 하지 않다.

해당 응답을 본 사람은 op가 무엇인지, path는 무엇을 의미하는지 어림짐작만 할 수 있을 뿐 정확한 의미를 알 수 없다.

대부분의 API는 이를 만족하지 못하고 있다. 따라서 온전히 응답에 대한 해석을 하기 위해 클라이언트 개발자와 서버 개발자 간에 공유하는 API 문서가 필요하다. 이 조건 때문에 대부분의 API는 Restful 할 수 없다. Self-descriptive 하지 않기 때문이다.

4) Hypermedia as the engine of application state(HATEOAS)

애플리케이션의 상태는 Hyperlink를 이용해 전이되어야 한다.
예를 들어 게시판 글을 등록하는 API를 설계한다고 가정한다.

HTTP/1.1 200 OK
Content-Type: application/json
[
	data: [
    	{
        	"id": 1,
            "title": "title1",
            "content": "content1"
        }
    ]
]

게시글을 등록하는 API를 만들 때 보통 POST /board/posts 요청에 대해 위와 같은 응답을 리턴한다. 이후 해당 데이터를 조회, 수정, 삭제하기 위한 API는 어떤 uri를 통해 요청을 보내야 하는지 API 문서를 통해 확인이 가능하다.

이 예시는 HATEOAS를 만족하고 있지 않다. HATEOAS를 만족하려면 title1에 대한 포스트에 접근할 때 하이퍼링크를 통해 이동해야 하기 때문이다. 따라서 HATEOAS를 만족하는 응답으로 수정하면 아래와 같은 형태가 될 것이다. Link라는 헤더를 사용한다.

{
  "seq": 1,
  "title": "title1",
  "content": "content1",
  "createdAt": "2022-04-21 14:30:00",
  "_links": {
    "self": {
      "href": "http://localhost/board/posts/1"
    },
    "get": {
      "href": "http://localhost/board/posts/1"
    },
    "delete": {
      "href": "http://localhost/board/posts/1"
    },
    "edit": {
      "href": "http://localhost/board/posts/1"
    }
  }
}

GET /board/posts 요청을 통해 전체 게시글을 출력하고 title1인 게시글에 접근하고자 할 때에도 GET /board/posts 요청과 GET /board/posts/1로 API 문서를 확인하여 문서에 정의된 API를 호출하는 것이 아니라 GET /board/posts 요청에 대한 응답의 link 헤더의 href 주소로 1번 게시글에 접근하는 것도 HATEOAS를 적용한 예이다.


다른 블로그들을 살펴보면 collection은 복수형이어야 하고 uri에는 동사를 포함하지 않아야 한다 등등 많은 제약조건을 지켜야 하는 것처럼 명시되어 있으나, Restful한 API의 본질은 위의 포스팅에서 언급한 것과 같다.

대부분의 API가 Restful할 수 없는 이유는 짧게 요약하면 REST 아키텍처에 적용되어야 하는 6가지 제한 조건 중 Uniform Interface라는 조건이 만족될 수 없기 때문이고, Uniform Interface가 만족될 수 없는 이유는 API가 self-descriptive하지 않고 HATEOAS가 적용되어 있지 않기 때문이다.


[참조] https://ko.wikipedia.org/wiki/REST
[참조] https://velog.io/@kjh03160/%EA%B7%B8%EB%9F%B0-REST-API%EB%A1%9C-%EA%B4%9C%EC%B0%AE%EC%9D%80%EA%B0%80
[참조] http://www.incodom.kr/RestFul_API
[참조] https://hanamon.kr/rest-api/
[참조] https://sas-study.tistory.com/369

profile
피드백은 언제나 환영입니다! :)
post-custom-banner

0개의 댓글