RESTful api (feat.이 API는 RESTful하지 않은 것 같습니다?)

미키오·2024년 4월 8일
0
post-thumbnail

0. 들어가며..

지난주 토요일.. GDG Songdo hello world24에서 남기범 개발자님의 RESTful API에 대한 세션에 참여하게 되었다.

사실 처음부터 이 세션을 들으려고 계획해서 갔다기보다는 세번째 세션을 뭘 들을지에 대한 고민을 하던 중 동행인으로부터 RESTful API이 뭐야? 설명하라 그러면 할 수 있어? 라는 질문을 받았을때 ‘음.. 클라이언트와 서버 간의 요청과 응답을 상태코드로 명확히 표현한거.? CRUD? JSON? 우리 API는 휴식중‘ 과 같은 모호한 답변밖에 할 수 없었다. 그런고로 이에 대한 솔루션을 얻기 위해 선택한 세션.

1. RESTful API란?

이 세션을 진행하신 남기범 개발자님께서도 평소에 코드리뷰를 하면서 '이 API는 RESTful하지 않은 것 같습니다?'와 같은 말을 하면서 RESTful 이라는 말에 대해 모호하다는 생각이 들었다고 하셨다.

1.1. API란 무엇인가

client 와 server 간에 리소스를 표현하고 상태를 전송하는 architecture

다시 말해 API란, 클라이언트, 서버와 같은 서로 다른 프로그램에서 요청과 응답을 주고 받을 수 있게 만든 체계이다.

1.2. REST란 무엇인가

REpresentational State Transfer

직역하자면 표현의 상태 이전? 정말 와닿지 않는다.

이에 대해 남기범 개발자님은 이 용어를 가장 먼저 소개된 Roy Fielding의 “Architectural Styles and the Design of Network-based Software Architectures”의 논문을 토대로 설명해주셨다.

Roy Fielding은 “How do I improve HTTP without breaking the web?” (웹을 망가뜨리지 않으면서 어떻게 HTTP를 입증할 수 있을까?) 에 대한 방안으로 REST를 제시했다.

1.3. 그래서 REST API는..

통합하자면 REST API란 REST 아키텍쳐 스타일을 따르는 API이고, REST란 월드 와이드 웹과 같은 분산 하이퍼미디어시스템을 위한 아키텍쳐 스타일, 제약 조건의 집합이다.

그가 제시한 REST를 만족하기 위해 지켜야할 제약조건은 총 6가지이다.

2. REST의 제약조건

  1. Client-Server
  2. Stateless
  3. Cache
  4. Layered System
  5. Uniform Interface
  6. Code on Demand (Optional)

남 개발자님에 의하면 HTTP 통신규약만 잘 준수해도, 대부분은 Client-Server, Stateless, Cache, Layered System은 잘 지켜지고 있다고 한다. 그러나 많은 경우 Uniform Interface에서 REST의 조건에 탈락하는 경우가 많다.

3. Uniform Interface의 제약조건

그렇다면 Uniform Interface의 제약 조건에는 어떤 것들이 있을까?

  • identification of resources
  • manipulation of resources through representations
  • Self-descriptive messages
  • Hypermedia As The Engine Of Application State

리소스가 URI로 식별되는 identification of Resources와

리소스를 만들거나(POST), 수정하거나(PUT | PATCH), 삭제(DELETE)할 때 HTTP 메시지에 표현을 담아, 전송해서 이를 달성하는 manipulation of resources through representations는 잘 지켜지고 있는 편이다. 문제는 나머지 둘이다.

3.2 Self-descriptive messages

Self- descriptive message : 메시지는 스스로를 설명해야 함.

→ 메시지 자체가 충분한 정보를 포함하여 어떤 작업을 해야 하는지 이해할 수 있어야 한다.

Self-descriptive한 메시지는 요청이나 응답에 모든 필요한 정보를 포함하며, 일반적으로 Content-Type, Accept 헤더 또는 Link 헤더와 같은 명시적인 선언을 통해 이를 달성한다.

예시를 좀 더 살펴보자.

Self-descriptive하지 않은 경우

(클라이언트 요청)

GET /users/1 HTTP/1.1
Host: example.com

(서버 응답)

HTTP/1.1 200 OK
Content-Type: text/plain

홍길동, hong@example.com

클라이언트는 응답의 구조나 의미, 다음에 할 수 있는 작업 등에 대한 아무런 정보도 가지고 있지 않다.

→ self-descriptive 위반

Self-descriptive한 경우

(클라이언트 요청)

GET /users/1 HTTP/1.1
Host: example.com
Accept: application/vnd.example.com.user+json

이 요청은 Accept 헤더를 통해 클라이언트가 application/vnd.example.com.user+json 타입의 응답을 원한다는 것을 명시하고 있다. 여기서 application/vnd.example.com.user+json는 사용자 리소스의 특정 표현을 요청하는 커스텀 미디어 타입으로 self-descriptive하다고 볼 수 있다.

(서버 응답)

HTTP/1.1 200 OK
Content-Type: application/vnd.example.com.user+json
Link: </users/1>; rel="self", </users/1/friends>; rel="friends"

{
  "id": 1,
  "name": "홍길동",
  "email": "hong@example.com"
}

이 응답은 Content-Type 헤더로 응답의 미디어 타입을 명시하고, Link 헤더를 통해 관련 리소스에 대한 링크를 제공하여 self-descriptive하게 만든다.

→ self-descriptive 준수

3.3. HATEOAS

또 다른 Uniform Interface의 제약 조건인 HATEOAS (Hypermedia As The Engine Of Application State) 에 대해서도 알아보자.

우선 변경주체인 client는 Hyperlink를 이용해 application의 상태를 전이해야한다.
위 사진처럼 글 목록 보기 → 글 쓰기 → 글 저장과 같이 상태를 전이하는 것을 애플리케이션 상태 전이라고 하고, hyperlink를 통해 상태를 전이했기 때문에 HATEOAS하다고 할 수 있다. 이러한 <a>태그와 같은 특성 덕분에 HTML은 대부분 HATEOAS를 만족한다.

그렇다면 HTML만 RESTful할 수 있나요?

HTML이 RESTful 아키텍처 원칙을 충족할 수 있는 좋은 예시 중 하나이긴 하지만, HTML만이 RESTful할 수 있는 유일한 포맷은 아니다. RESTful 아키텍처는 특정 포맷에 국한되지 않고, 자원(리소스)의 상태를 전송하는 데 필요한 모든 요구사항을 충족시키는 다양한 미디어 타입을 지원한다.

예를 들어, JSON 또한 HATEOAS를 준수하며 작성할 수 있다.

POST /books HTTP/1.1
Content-Type: application/json
{
	"title" : "나만 알아보게 코드짜기"
}
HTTP/1.1 204 No Content
Location: /books/1
Link: </books/>; rel="collection"

이 예시 코드는 HATEOAS 원칙의 핵심 요소를 포함하고 있다. 클라이언트가 새로운 책을 생성하는 POST 요청을 보내고, 서버가 204 No Content 상태 코드와 함께 Location 헤더를 반환함으로써 새로 생성된 리소스의 URI를 제공한다.

또한, Link 헤더를 통해 이 새로운 리소스가 속한 컬렉션의 링크를 제공한다.

HATEOAS를 준수한다는 것은 API 응답이 다음 가능한 상태 전환에 대한 정보(주로 하이퍼링크)를 포함해야 한다는 것을 의미한다. 이 경우, Link 헤더는 클라이언트가 책의 컬렉션으로 돌아갈 수 있는 URL을 제공하여, 클라이언트가 서버에 대해 사전에 알고 있는 정보 없이도 가능한 다음 행동을 탐색할 수 있게 해준다.

HAL

남 개발자님은 HATEOAS를 준수하는 방법으로 HAL JSON을 제시하셨다.

HAL은 Hypertext Application Language의 준말로, JSON이나 XML 코드 내에 외부 리소스에 대한 하이퍼링크를 정의하기 위한 데이터 타입이다. HAL을 채택하는 API는 오픈 소스 라이브러리 사용을 단순화하고 JSON 또는 XML을 사용하여 API와 상호 작용할 수 있는 것에 목표를 둔다.

대표적인 HAL은 두 가지로,

  1. application/hal + json
  2. application hal + xml

이 존재한다.

HAL에서는 두 가지 개념에 기반하여 요소를 표현할 수 있다.

바로 리소스와 링크이다.

  • 리소스 : 표준 데이터 필드로 구성
  • 링크 : 타겟 URI가 있으며, 보통 _self 필드가 링크 필드가 된다.

아래는 application / hal + JSON의 예시이다.

{"data" : { // HAML JSON의 리소스 필드
	"id": 1,
	"title": "제목",
	"content" : "이 책은 엄청난 내용을 담고 있다."
}
  "_links": { // HAL JSON의 링크필드
    "self": {
      "href": "http://example.com/api/book/hal-cookbook"
    },
    "next": {
      "href": "http://example.com/api/book/hal-case-study"
    },
    "prev": {
      "href": "http://example.com/api/book/json-and-beyond"
    },
    "first": {
      "href": "http://example.com/api/book/catalog"
    },
    "last": {
      "href": "http://example.com/api/book/upcoming-books"
    }
  },
  "_embedded": {
    "author": {
      "_links": {
        "self": {
          "href": "http://example.com/api/author/shahadat"
        }
      },
      "id": "shahadat",
      "name": "Shahadat Hossain Khan",
      "homepage": "http://author-example.com"
    }
  },
  "id": "hal-cookbook",
  "name": "HAL Cookbook"
}

제언

이처럼 Roy Fielding이 강조하는 진정한 의미의 RESTful api를 구현하기란 매우 어렵다. 우선 RESTful api라는 용어와 이를 준수하는 요건 기준이 까다롭다. 일례로, Roy는 Microsoft2016의 REST api 가이드 또한 uniform interface에 위반한다며 그것은 REST api가 아닌 편리한 HTTP API 가이드라인일 뿐이라고 반박했다.

또한, Self-descriptive하며 HATEOAS를 준수하는 과정 자체가 많은 정보를 필요로 한다. 그 과정에서 여러 요청을 보내거나 필요 이상의 정보를 받게 되며 많은 시간과 비용을 요구한다.

이러한 단점 때문에 남 개발자님은 “무조건 RESTful 한게 좋을까”라는 의문점을 던져주시며 세가지 방향성을 알려주시며 강의를 마무리하셨다.

  1. 최대한 Roy의 진정한 REST api 구현
  2. 어느 정도 REST 원칙을 참고한 HTTP api 구현 (ex. microsoft)
  3. 다른 API를 선택 (ex. GraphQL)

최근 기업 공고를 보면 RESTful api 를 준수하는 분이라던가 면접 질문에 ‘RESTful api란 무엇인가요’가 단골 질문일 정도로 정말 자주 사용하는 개념이다. 하지만 이렇게 통상적으로 널리 알려진 개념치고는 해석도 제각각이고 (창시자인 Roy와 Microsoft의 정의가 다름), 생각보다 깊고 복잡하다는 점에서 놀랐다. 사실 이 글도 따로 분리할 생각은 없었는데 쓰다보니 GDG 후기의 절반 이상을 잡아 먹어서 분리를 강행했다.

또한 2년 전에 API에 대해 처음 배우면서 이 블로그에 RESTful API에 대해 정리하면서 Microsoft의 정의를 가져왔으니 Roy님이 보시면 뒷목 잡으실 것 같다.

이번 정리를 통해서 프로그래밍에서의 용어 분석의 중요성과 그동안 잘못 알고 있었던 RESTful API에 대한 오해를 조금은 풀고 갈 수 있었던 것 같다. 다음 프로젝트에서는 이번 정리를 통해 정립한 REST한 api를 구축해보거나 GraphQL과 같은 다른 대안을 활용해보고 싶다.

이러한 생각의 기회를 마련해주신 GDG와 남기범 개발자님께 감사드린다.

📚 Bibliography

RESTful API란 무엇인가요? - RESTful API 설명 - AWS

Day1, 2-2. 그런 REST API로 괜찮은가

HATEOAS를 모르면 당신이 알고 있는 REST API는 REST API가 아니라고 장담할게요.

Hypertext Application Language

profile
교육 전공 개발자 💻

4개의 댓글

comment-user-thumbnail
2024년 4월 9일

김영한님 말에 따르면... 그냥 실무에서 REST API를 얘기하면 포스팅에서 나와있듯이 대부분이 Uniform Interface를 지키지 않은 API이기에 그냥 아~ HTTP API 이이야기 하는구나 라고 생각하면 된다고 하네요. 좋은 글 감사합니다~

1개의 답글
comment-user-thumbnail
2024년 4월 9일

알수록 뇌절인 REST API.. 정리 잘해주셔서 감사합니다! 기회가 된다면 REST API 설계도 도전해보고 싶어요

1개의 답글