개인 프로젝트 진행 후 이력서와 함께 GitHub 링크를 올려 피드백을 받은 적이 있다.
그 날 여러 댓글이 달렸고, 좋은 내용은 없었던 것 같다.
그 중 유독 벡앤드 하실거면 웬만하면 REST API로 작성하라는 댓글이 눈에 띄었다.
왜냐면 그 동안 필자는 스스로 REST API 형식으로 작성하고 있다고 믿고 있었기 때문이다.
그래서 오늘은 REST API를 정복하고 제대로 된 백엔드 개발자로서 거듭나 보고자 한다.
REST는 Roy T. Fielding(로이 토마스 필딩)이라는 사람에 의해서 창시되었다.
로이는 웹 간의 상호 호환성을 지키면서 HTTP 프로토콜을 향상시킬 방법에 대해 고민하였고, 그 결과로 내놓은 것이 REST이다.
로이는 REST를 "네트워크 기반의 소프트웨어 아키텍처에서 사용되는 하나의 디자인이자 아키텍처 스타일"이라고 설명했다.
즉, REST라는 것은 아키텍처 스타일일 뿐이다. 꼭, HTTP일 필요는 없고 그것만을 고려해서 만든 것도 아니다.
아키텍처 스타일이란 제약 조건의 집합을 말한다.
그러한 제약 조건을 잘 지키는 경우 아키텍처 스타일을 적용했다고 표현할 수 있다.
REST는 특이하게 하이브리드 아키텍처 스타일이라고도 불리는데, 여러 가지 아키텍처 스타일로 이루어져 있기 때문이다.
결국 REST API라는 것은, 네트워크 기반의 소프트웨어에서 REST가 되기 위한 제약 조건을 잘 지켜서 작성된 API를 말한다.
그렇다면 그러한 제약 조건이 무엇인지 이해하고 지키기만 한다면 REST API를 작성할 수 있을 것이다.
REST의 목적은
로이는 REST를 위한 조건을 약 6가지 정도 제안했다.
하나하나 살펴보도록 하자.
클라이언트와 서버를 분리하는 아키텍처를 사용하는 것이다.
둘의 관심사를 분리하여 서버의 역할을 간소화 함으로써, 서버의 확장을 늘리고 사용자 인터페이스는 여러 플랫폼에 대한 이식성을 높인다.
서버는 요청에 대한 상태를 서버에 저장하지 않아야 한다는 특징이다.
클라이언트에서 보내는 요청에 모든 필요 정보가 포함되어 있어야 하며 서버는 상태를 저장하지 않는다.
세션 같은 것을 사용하면 Stateless하지 않다고 할 수 있다.
캐시 처리가 가능해야 한다. 요청에 대한 응답에는 암묵적으로 또는 명시적으로 캐시 처리 가능 여부가 따라야 한다는 내용이다.
REST 아키텍처 스타일에서 가장 중요한 내용이자 다른 아키텍처 스타일과 차별화 되는 항목이다.
Uniform Interface에서 REST를 위해 제안하는 4가지 인터페이스 제약 조건이 존재한다.
리소스의 식별이 가능해야 함을 의미한다.
보통은 HTTP 통신에서 REST라는 표현을 많이 사용하기 때문에, 나와 같은 웹 백엔드 개발자라면 URI라는 고유 식별자를 통한 리소스 식별을 의미한다고 생각하면 될 듯 하다.
리소스의 조작을 representations을 통해 하라는 뜻이다.
요청에 대한 응답은 자원 자체가 아닌 자원의 표현(representation)으로 응답하라는 뜻이다.
즉, 리소스 자체가 아닌 리소스의 상태를 반영하는 정보(representation)를 통해서 응답을 조작하라는 뜻인 것 같다.
representations에 대한 내용은 링크에 잘 정리되어 있다.
대충 요약하면, representation은 리소스의 특정 시점의 상태를 반영하는 정보이다.
representation을 XML, JSON이런 것들로 표현하는 글들이 많은데, 위의 내용에 따르면 리소스에 대한 특정 시점의 정보 데이터를 그런 형태로 표현할 수 있다고 보는게 더 맞지 않을까 싶다. ( 개인적인 의견이다. )
메시지는 스스로 자신에 대해 설명할 수 있어야 한다는 제약이다.
응답에는 클라이언트에서 어떤 작업을 할 때 필요한 모든 데이터가 포함되어야 하며, API 문서가 추적 가능하거나 본문에 존재해야 한다.
이로 인해 서버나 클라이언트가 변경되더라도 메시지만 보고 모든 해석이 가능해 진다.
하이퍼미디어(링크)를 통해서 애플리케이션의 상태 전이가 가능해야 한다.
상태 전이란 해당 URI에서 사용자가 다음으로 취할 수 있는 행동들을 말한다.
로이는 "애플리케이션 상태 엔진 및 API가 하이퍼 텍스트에 의해 구동되지 않는 경우 RESTful이 될 수 없으며 REST API가 될 수 없다."고 표현했다.
이는 상태 전이는 하이퍼미디어를 통해야만 한다는 내용이기도 하고, 현재 URI에서 하이퍼미디어를 통한 상태 전이가 가능하려면 결국 응답에 하이퍼미디어가 포함되어 있어야 한다는 의미이기도 하다.
그렇다고 "링크가 포함되어 있음 = HATEOAS" 인 것은 아니다.
HATETOAS의 목적은 서버가 다음 액션에 대한 선택지를 클라이언트에게 전달함으로서 서버와 클라이언트 간의 의존을 없애 확장을 보조하기 위한 것이지, 단순히 링크를 포함하는 개념으로만 오해하면 안 된다.
예를 들어 서버 쪽에서 특정 리소스에 대한 URI가 변경된다고 가정해 보자.
non-HATEOAS 형태의 아키텍처에서는 클라이언트 쪽에 URI가 하드 코딩되어 있을 확률이 높다.
이러한 구조는 서버의 URI 변경으로 인해 클라이언트에 하드 코딩된 URI를 함께 변경해야 하기 때문에 유연하지 못 하며 서로 의존적인 형태이다.
이렇게 클라이언트와 서버가 의존적이지 않으면서 하이퍼미디어(링크)를 통해서 애플리케이션의 상태 전이가 가능하면 되는 것이지 꼭 링크가 포함되는 형태만이 정답은 아니라는 것이다.
하지만 현재 HTTP 통신을 보면 링크를 포함하는 것 외에는 딱히 방법이 없다고 생각하고, 미래에 어떻게 진화할지 모르는 HTTP나 다른 네트워크 프로토콜에 따라 충분히 다를 수 있다는 정도만 알면 되지 않을까 싶다.
왜 이러한 HATEOAS를 지켜야 하는 걸까?
HTTP가 처음 나온 이유를 생각해 보면 된다.
옛날에는 문서가 단순 텍스트만으로는 이루어져 있었기 때문에 필요한 참고 문헌들을 일일이 찾아 읽는 것이 번거로운 문제가 있었다. 이러한 문제를 해결하기 위해 하이퍼 텍스트라는 개념을 이용해 참조 문헌을 간편하게 참조하고자 했고 그래서 나온 것이 HTML이다. 그리고 HTML을 웹 상에서 주고 받기 위한 프로토콜이 HTTP이다.
즉, HTTP란 처음부터 하이퍼텍스트(미디어)를 통한 상태전이(참조)가 주 목적이기 때문에 응답에 상태전이가 가능한 링크가 포함되어 있어야 하는 것이 정상이다.
애초에 참조가 필요 없는 응답이면 상관없지만, 참조가 필요한 응답에서 참조 링크를 응답 자체에 포함시키는 방식이 아니라면 문제가 있다는 것이다.
이렇게 생각해 보면 너무나도 당연한 내용인데 우리가 잊고 있었던 것일 수도 있다.
보통 HTML 응답에 하이퍼텍스트(링크)가 포함되어 링크를 통해 상태전이가 이루어지지만, 점점 프론트의 역할이 커지면서 HTML은 화면을 전송하는 용도이고 링크는 javascript로 만들어내고 있던 것이다.
이는 Json과 같이 HTML이 아닌 다른 응답 형태에서도 적용되어야 한다. HTML에만 하이퍼텍스트를 포함시키는 것이 아니다. 결국 HTTP 통신을 사용한다면 위와 같은 방식의 응답이 당연시 되어야 한다는 것이다.
응답 형태가 무엇이 되었든 응답에는 하이퍼텍스트가 포함되어야 하고 그를 통한 상태전이가 가능해야 한다는 것이다. Json, Xml 무엇이든 형태가 변했다고 하이퍼텍스트가 빠질 이유는 어디에도 없다.
물론 이러한 방법이 잘못되었냐고 하면 그런 것은 아니다. 위의 방법도 HTTP 통신을 사용한 하나의 방법일 뿐이다.
하지만 그것을 REST라고 불러서는 안 되며, 진정한 HTTP의 통신의 순정을 지키는 REST는 HATEOAS를 지켜야 한다는 것이다.
서버가 미들웨어 구성 요소를 추가하여 계층화할 수 있어야 한다는 내용이다.
요청을 하는 클라이언트와 응답을 보내는 서버 사이에 보안 계층, 캐싱 계층 등 여러 계층이 있을 수 있다.
하지만 각 레이어는 바로 다음 레이어만 바라보아야 하고 중간 계층이 요청이나 응답에 영향을 미치지 않아야 된다.
즉, 클라이언트는 최종 서버에 연결되어 있는지 중간에 연결되어 있는지 알 수 없어야 한다는 뜻이다.
서버가 실행 코드를 클라이언트에 보낼 수 있어야 하는 것을 말한다.
클라이언트는 서버에 코드를 요청할 수 있고, 서버는 자바스크립트나 자바 애플릿과 같은 실행 가능한 코드를 제공한다.
이는 배포 후 기능을 다운로드 할 수 있도록 구현하여 클라이언트의 사전 구현을 단순화 하는 역할을 한다.
선택사항이기 때문에 꼭 지켜야 할 필요는 없다.
사실 일반적으로 REST API라고 하면 많은 사람들이 HTTP method를 사용해서 행위를 표현하고 식별자를 계층형으로 표현하고 등등.. 이런 것들을 접해 왔을 것이다.
필자의 구글링 한계로는 해당 내용들이 로이 토마스 필딩이 제안한 REST의 개념에 포함되는 것인지는 모르겠다.
하지만 중요한 것은 REST API가 성립하기 위해서는 위에서 설명한 6가지 조건들이 반드시 지켜져야만 한다는 것이다.
그리고 method를 사용하고 계층이고 뭐고 하는 그런 개념들은 Microsoft사에서 제안한 REST API 작성 가이드라인에 포함된 내용이지 않을까 싶다.
하지만 로이가 제안을 했든 안 했든 그걸 떠나서 통상적으로 REST API라고 하면 지켜지고 있는 규칙들이 있는데 이번에는 그 내용들에 대해서 정리해 보고자 한다.
통상적으로 사용되는 REST API는 크게 자원(Resource), 행위(Verb), 표현(Representations)로 이루어져 있으며, 자원은 식별자(URI)가 가리키는 목표(타겟)를 의미하고 행위란 HTTP의 POST, GET, PUT, DELETE와 같은 메서드를 말한다. 아까 위에서 설명한 Representation 글을 읽고 오면 된다.
REST API를 지키기 위한 디자인 규칙은 다음과 같다.
1. 행위는 URL에 포함하지 않고 명사를 사용한다.
2. 행위는 HTTP Method(GET, POST, PUT, DELETE)로 표현한다.
3. 소문자를 사용한다.
4. URL의 마지막에 슬래시(/)를 포함하지 않는다.
5. 언더바(_) 대신 하이픈(-)을 사용한다.
6. 단수형 보단 복수형을 사용한다.
7. 확장자는 URI에 포함하지 않는다.
8. 리소스 간에 연관(계층) 관계가 있는 경우 상위 리소스부터 계층적으로 작성한다
9. 복수형을 사용한다. ( 단수를 사용해도 되지만, 혼용은 추천하지 않는 듯 하다. )
위의 내용들이 있다.
필자의 개인적인 의견으로는 위의 내용들은 사실상 REST API가 되기 위한 조건 보다는 REST API 작성을 위한 컨벤션 정도가 아닐까 싶다.
또는, 위의 내용들도 REST API를 위한 조건에 해당되고 거기에 추가로 로이가 바라는 REST의 개념이 지켜져야 진정한 RESTful API가 되는 것이 아닐까 싶기도 하다.
이 부분을 정확히 잘 모르기 때문에 너무 신뢰하지 않았으면 한다.
내용을 정리하고 나니 완벽한 REST API가 가져야 할 조건들을 알 수 있었다.
이제 나도 어디가서 "그건 REST API가 아닙니다(?)"를 시전할 수 있게 되었다.