셀메이트의 API 대부분은 REST 를 기반으로 설계되고 만들어지고 있습니다. 그렇다면 REST 가 무엇이고 REST API 또는 RESTful API 라고 부를수 있는 설계 원칙과 특징에 대하여 이번 컨퍼런스를 통하여 발표를 진행 하였습니다.

REST?

  • REST는 REpresentational State Transfer 의 약자로, 분산 하이퍼미디어 시스템(ex. web)을 위한 소프트웨어 프로그래밍 아키텍처 스타일입니다.
  • REST라는 개념은 Roy T.Fielding이 자신의 박사학위 논문에서 처음 소개하였으며, 기본적으로 HTTP 프로토콜을 더욱 잘 활용할 수 있도록 만들어진 아키텍처 스타일입니다.

REST의 일반적인 오해

REST API 에 대하여 정의를 검색해보면 많은 자료들에서 REST를 아래와 같이 정의하고 있습니다.

HTTP URI(Uniform Resource Identifier) 를 통하여 자원(Resource)을 명시하고,

HTTP Method(POST, PUT, GET, DELETE) 를 통하여 해당 자원에 대한 CRUD operation을 적용하는 것을 의미한다.

하지만 로이 필딩의 블로그 글중 이와 관련하여 작성한 포스팅(It is okay to use POST)의 일부를 발췌하여 보면

Some people think that REST suggests not to use POST for updates. Search my dissertation and you won’t find any mention of CRUD or POST.

The only thing REST requires of methods is that they be uniformly defined for all resources.

As long as the method is being used according to its own definition, REST doesn’t have much to say about it.

위 내용을 요약하면 자신의 논문에서는 CRUD 또는 POST에 대한 언급은 없으며, REST는 오직 모든 자원(Resource)에 대하여 균일하게 정의되는 것이며 그 방법이 독자적인 정의를 따라 사용되고 있는 한 REST는 그것에 대하여 이야기하지 않는다. 라고 이야기 합니다.

이는 로이 필딩이 정의한 REST는 CRUD나 HTTP에 종속되지 않고 REST의 조건을 충족하는 경우에 REST 아키텍처 스타일이라 부를수 있으며, REST 아키텍처가 성립하는데 CRUD 의 유무는 중요하지 않다. 라는 의미로 받아들일 수 있다고 봅니다.

REST의 6가지 제약 조건

기본적으로 REST는 HTTP 프로토콜을 제대로 활용하자라는 취지로 만들어진 아키텍처 스타일로 HTTP 프로토콜을 잘 따르면 대부분의 REST 제약 조건에 부합한다고 볼 수 있습니다.

  1. client-server (클라이언트 / 서버 구조)
    • 클라이언트와 서버는 분리되어 독립적으로 역할이 명확히 구분됩니다.
    • HTTP 프로토콜의 요청과 응답 구조
  2. Stateless (무상태성)
    • 무상태성은 첫번째로 언급한 client-server 구조의 상호작용에 대한 조건입니다.
    • REST는 HTTP 프로토콜과 같이 서버가 클라이언트의 상태를 보존하지 않는 조건을 가집니다.
    • 서버측에서는 클라이언트의 상태 정보를 저장하지 않습니다.
  3. Cacheable (캐시 처리 가능)
    • HTTP 프로토콜 헤더 필드의 Cache-Control 과 같이 캐시 처리가 가능하다는 조건입니다.
  4. Layed System (계층화)
    • 서버를 다중 계층으로 구성이 가능하다는 조건입니다.
    • 계층형 시스템 아키텍처를 사용할 수 있으며 중계 서버를 두어 네트워크와 프로세서 사이에 로드 밸런싱을 가능하게하여 시스템의 확장성을 확보할 수 있습니다.
  5. Uniform Interface (인터페이스의 일관성)
    • 클라이언트와 서버간의 상호작용을 위한 인터페이스는 일관되어야 한다는 조건입니다.
    • Uniform Interface 의 제약조건이 가장 지켜지기 어려우며 이 제약 조건을 충족시키지 못하는 API 가 대부분이라고 볼 수 있습니다.
    • 아래에서 좀 더 자세히 다루도록 하겠습니다.
  6. Code on demend (Optional)
    • 서버가 클라이언트에서 실행할 수 있는 코드를 전송할 수 있다는 조건입니다.
    • 해당 조건은 Optional한 조건으로 로이 필딩도 따로 다루고있지 않습니다.

Uniform Interface 제약조건

  1. 자원의 식별 (Idenfification of Resources)

    • URI (Uniform Resource Identifier) 를 통하여 자원(Resource)를 식별해야 합니다.
  2. 표현을 통한 자원의 조작 (manipulation of resources through representation)

    • 표현을 통하여 자원의 상태를 조작해야합니다.
    • 표현은 HTTP Method (POST, PUT, GET, DELETE) 가 이에 해당됩니다.
  3. 자기 서술적 메세지 (self-descriptive messages)

    • 자원의 요청이나 응답에는 자신에 대한 모든 정보가 포함되어야 합니다.

    Example

    Request

    1
    
    GET /users
    

    위 요청이 self-descriptive 를 충족하기 위해서는 목적지 에 대한 정보가 필요합니다. 그러므로 아래와 같이 목적지가 추가 되었을 경우, self-descriptive 를 충족했다고 판단할 수 있습니다.

    1
    2
    
    GET /users
    Host: www.example.org
    

    Response

    1
    2
    3
    4
    
    HTTP/1.1 200 OK
    Content-Type: application/json
    
    [{ "op": "add", "path": "/hello", "value": ["world"] }]
    

    위 응답 형태는 일반적으로 json 데이터로 응답 받는 경우의 응답 구조이지만 self-descriptive 를 충족했다고 보기에는 어렵습니다.

    json으로 데이터가 응답된다라는 정보가 헤더에 들어있으나 내부 데이터가 무엇으로 정의되어 있는지에 대한 설명이 없기때문입니다.

    self-descriptive를 충족하기 위해서는 아래와 같이 응답 데이터가 어떻게 정의되어 있는지 상세하게 상태를 전달해야 합니다.

    1
    2
    3
    4
    
    HTTP/1.1 200 OK
    Content-Type: application/json-patch+json
    
    [{ "op": "add", "path": "/hello", "value": ["world"] }]
    

    위와 같이 json-patch 명세로 데이터를 해석할 수 있음을 상세히 정의해주어야 비로소 self-descriptive를 충족 했다고 할수 있습니다.


  4. HATEOAS (hypermedia as the engine of application state)

    • self-descriptive message 와 같이 가장 지켜지기 어려운 제약 조건입니다.
    • Hypermedia (link) 를 통하여 자기 자신에 대한 정보가 전달되어야 하며 이를 통하여 상태 전이가 가능해야 한다는 제약 조건입니다.

    Example

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    GET www.example.org/users
    
    {
        "data": [
            {
                "id": 1,
                "name": "a"
            },
            {
                "id": 2,
                "name": "b"
            }
        ],
        "links": {
            "self": "http://www.example.com/users?page=1",
            "first": "http://www.example.com/users?page=1",
            "last": "http://www.example.com/users?page=1",
        }
    }
    

    위와 같이 자기 자신과 상태 전이가 가능한 정보가 links 라는 메타데이터로 전달되어야 합니다.

    위 예시는 매우 간단히 설명을 위한 예시이나 실제로는 자원의 삭제, 수정 등 상태 전이를 위한 hypermedia 링크를 제공합니다.


마치며..

우리 개발그룹은 사실 RESTful API 를 사용하지 않습니다. RESTful API 의 제약 조건을 지키지 않는다고 하여 그것이 나쁜 API가 아니며, 오히려 고객의 요구를 충족할 수 있도록 우리만의 아키텍처 스타일을 구축한다면 REST 를 지켜가며 개발하는 것보다 더 나은 가치를 실현할 수 있을거라고 생각합니다.

위 포스팅은 DEVIEW 2017 그런 REST API로 괜찮은가 를 참고하여 작성되었습니다.