[WEB] REST(feat. 로이 필딩과 잘못된 REST)

김민제·2024년 4월 8일

WEB👨‍🎓

목록 보기
1/1
post-thumbnail
  • 저는 스프링으로 웹백엔드를 구성하며 @RestController라는 어노테이션으로 HTTP Method 통신을 위화감 없이 사용하고 있었고 REST를 “HTTP URI(Uniform Resource Identifier)를 통해 자원(Resource)을 명시하고, HTTP Method(POST, GET, PUT, DELETE)를 통해 해당 자원을 상태를 전송하는 것”정도로만 알고 있었습니다.
  • 하지만 면접을 준비하며 “내가 정말 REST API를 사용하여 개발하고 있는 것일까?”라는 생각과 이에 대한 공부가 너무 얕은 것을 깨달았고 이에 대해 정확하게 정리하고 넘어가고자 글을 쓰며 공부하고자 합니다!

REST(REpresentational State Transfer)

REST란?

  • REST(Representational State Transfer)는 월드 와이드 웹과 같은 분산 하이퍼미디어 시스템을 위한 소프트웨어 아키텍처의 한 형식입니다.
  • REST는 Roy T. Fielding이 자신의 박사학위 논문 “Architectural Styles and the Design of Network-based Software Architectures” 에서 처음 소개하였습니다.
  • REST는 기본적으로 웹의 기존 기술과 HTTP 프로토콜을 활용하기 때문에 웹의 장점을 최대한 활용할 수 있는 아키텍처 스타일입니다.
  • 여러 자료들을 찾아보면 REST의 개념에 대해 다음과 같이 설명된 곳이 많습니다.

HTTP URI(Uniform Resource Identifier)를 통해 자원(Resource)을 명시하고, HTTP Method(POST, GET, PUT, DELETE)를 통해 해당 자원에 대한 CRUD Operation을 적용하는 것을 의미한다.

  • 하지만 REST를 정의한 로이 필딩이 작성한 블로그 글인 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. …(중략)… As long as the method is being used according to its own definition, REST doesn’t have much to say about it.

  • 해당 글의 첫 문단을 간략하게 번역해보면 다음과 같습니다.

일부 사람들은 REST가 업데이트를 위해 POST를 사용하지 말라고 제안한다고 생각합니다. 하지만 내 논문을 검색해보면 CRUD나 POST에 대한 언급은 없습니다. PUT에 대한 언급도 HTTP의 쓰기-백 캐싱 부재와 관련해서만 나타납니다. 구체적인 명세를 제공하지 않은 주된 이유는 HTTP에 의해 정의된 메소드들이 웹의 아키텍처 정의의 일부이지, REST 아키텍처 스타일의 일부가 아니기 때문입니다. GET의 검색:자원 이중성을 제외하고, 특정 메소드 정의는 REST 아키텍처 스타일에 별로 중요하지 않으므로, 그것들에 대해 스타일 논의를 하는 것이 어렵습니다. REST가 메소드에 요구하는 유일한 것은 모든 자원에 대해 일관되게 정의되어야 한다는 것입니다(즉, 중재자가 요청의 의미를 이해하기 위해 자원 유형을 알 필요가 없어야 합니다). 메소드가 자체 정의에 따라 사용되는 한, REST는 그것에 대해 많은 말을 하지 않습니다.

  • 로이 필딩은 위 글에서 본인이 작성한 REST에 대한 논문에 CRUD에 대한 언급이 없다는 말을 하고 있습니다. 또한 “메서드가 자체 정의에 따라 사용되는 한 REST는 그것에 대해 많은 말을 하지 않는다”라고 말하고 “REST 아키텍처 스타일이 특정 HTTP 메소드의 사용에 대해 엄격한 규칙을 제시하지 않는다”라고 말하고 있습니다.
  • 저는 이 말을 “REST는 CRUD나 HTTP 메소드에 종속적인 의미가 아니라 모든 자원에 대해 메소드가 일관되게 정의되고 사용되고 REST의 제한 조건들을 잘 지키기만 한다면 그것은 REST 아키텍쳐 스타일이다. 즉, REST 아키텍쳐가 성립하는데 CRUD 등의 유무는 상관관계가 없다.”라는 뜻으로 받아들였습니다.
  • 정리해보자면 REST는 REST 아키텍쳐의 제약조건들을 지킨 아키텍쳐 스타일이고 위 HTTP METHOD나 CRUD를 통해 REST를 설명한 글은 REST 제약조건을 통해 아키텍쳐 스타일을 사용하는 일부분에 대해서 설명해놓은 글이라고 생각합니다!
  • 이에 대해 제가 이해한 것을 이해하기 쉽게 설명해보자면 REST는 커튼을 설계할 때 이를 위로 말아올리는 형식으로 만들지 옆으로 걷는 형식으로 만들지 등의 구조를 정하는 것처럼 소프트웨어를 설계하기 위한 구조에 대해 로이 필딩이 생각한 best practice를 정해놓은 것입니다!
  • REST와 HTTP의 상관관계에 대해서는 아래 REST API에 대해 공부할 때 더 살펴보기로하고 REST의 제약 조건에 대해서 알아보겠습니다.

REST 아키텍쳐의 6가지 제약 조건

클라이언트/서버 구조

  • 클라이언트-서버 구조 조건의 원칙은 관심사의 분리(Seperation of concern)입니다.
  • 아키텍처를 단순화시키고 데이터의 저장에 대한 관심사사용자 인터페이스에 대한 관심사를 분리함으로써 클라이언트-서버의 각 파트가 독립적으로 발전될 수 있도록 해줍니다.

무상태성(Stateless)

  • 무상태성은 위에서 말한 제약 조건인 클라이언트/서버 구조의 상호작용에 대한 내용입니다.
  • 세션에 대한 정보는 전부 클라이언트 쪽에 저장되어 서버 측에서는 클라이언트의 상태를 저장하지 않는다는 것입니다.
  • 무상태성은 서버가 요청에 대한 정보를 저장하지 않기 때문에 리소스 확보의 용이성과 구현의 단순화라는 이점을 얻을 수 있습니다. → 확장성 증가
  • 하지만 무상태성이 가져오는 단점으로 서버측에 요청에 관한 정보가 저장되지 않기 때문에, 반복되는 요청이 발생하여 네트워크 성능을 저하시킬 수 있고 상태를 클라이언트에 저장하기 때문에 서버 측의 일관된 제어를 받을 수 없다는 것이 있습니다.

캐시 처리 가능(Cacheable)

  • 캐시 처리 가능 제약 조건은 응답데이터가 cacheable한 지, non-cacheable한지 지정되어야 한다는 것입니다.
  • 응답이 cacheable한 경우, 클라이언트 캐시에 동일한 요청에 대해 해당 응답데이터를 나중에 재사용할 수 있는 권한이 부여되어 서버-클라이언트 간의 통신 지연 속도를 감소시킬 수 있습니다. → 네트워크 효율성
  • 하지만 캐시내에 서버가 오래된(stale) 데이터를 가지고 있다면 요청-응답에 대한 신뢰성(reliability)이 저하될 수 있다는 단점이 있습니다.

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

  • “구성요소(클라이언트, 서버 등) 사이의 인터페이스는 균일(uniform)해야한다.”
  • 인터페이스 일관성 제약조건은 컴포넌트간의 인터페이스를 일반화 시킴으로 전체적인 시스템 아키텍쳐를 단순화시키고 상호작용의 가시성을 향상시키자는 것입니다.
    • 즉, 각 컴포넌트(서버, 클라이언트) 사이의 연결인 인터페이스를 약속된 형태로 정의하자는 것
  • 이 방식의 장점은 서버 입장에서는 어떤 클라이언트인지 몰라도 표준에 의한 응답을 주면 되고, 클라이언트 입장에서는 hypertext를 통한 이동을 표준화된 방식으로 하기 때문에 해당 서버의 특징을 알 필요가 없다는 것! 즉, 서로의 특성을 알지 못해도 소통이 가능하다는 것입니다!
  • 각 컴포넌트(서버, 클라이언트 등)를 완벽하게 분리시키고 각 컴포넌트 사이의 연결은 표준화된 형태의 인터페이스로 제공한다면 “각 컴포넌트간의 결합도는 약해지고 컴포넌트의 응집도는 향상된다."는 SOLID 원칙의 ISP(Interface Segregation Principle)을 지키는 것과 같은 효과를 낼 수 있을 것입니다.
  • 하지만 인터페이스 일관성은 각 컴포넌트간 교환되는 정보, 데이터는 애플리케이션의 요구에 의한 것이 아닌 표준화된 형태로 변환되어야 하기 때문에 효율성(efficiency)은 저하됩니다.

인터페이스 일관성의 4가지 제약조건

1. 자원의 식별(identification of resources)

  • 리소스를 식별하는 방법이 동일해야 합니다. 저희는 보통 URI를 쓰기 때문에 URI를 통해 자원을 식별해야 합니다.

2. 표현을 통한 자원의 조작(manipulation of resources through representation)

  • 여기서 표현은 특정한 상태의 자원에 대한 표현을 말합니다.
  • 자원을 조작하기 위한 내용은 자원을 식별하기 위한 공간과 분리되어야 한다는 것입니다.
  • 리소스의 표현계층(representation)을 리소스의 식별자(URL)로부터 분리한 것은 REST에서 아주 주요한 관점입니다.
  • HTTP에서는 메소드가 이에 해당됩니다.

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

  • 메시지는 스스로에 대하여 설명을 해야한다는 것입니다. 즉, 요청이나 응답 메시지에는 이를 이해하기 위한 모든 정보가 포함되어야 합니다.
  • 요청에는 자원과 메시지만 있는 것이 아니라 목적지(domain) 정보도 포함되어야 하고, 응답 데이터에는 content-type과 그 정보를 해석하기 위한 정보도 포함되어야 한다는 말입니다.

4. 애플리케이션 상태의 엔진으로써 하이퍼미디어(hypermedia as the engine of application state)

  • 상태의 변경은 하이퍼 링크를 통해서 해야합니다.
  • HTML과 같은 하이퍼 미디어를 통하여 클라이언트에게 애플리케이션의 상태를 변경할 수 있는 인터페이스를 제공해야한다는 것입니다!
    • URI를 통해 웹 페이지 내에서 이동을 하는 것이 아닌 화면에 랜더링된 HTML 앵커 태그 등을 통해 페이지 이동을 해야한다는 것이겠죠!
  • 이 부분의 설명을 들어보면 백엔드보다는 프론트엔드의 영역이 아닌가?라는 생각이 듭니다! 서버에서 해당 앵커 태그가 담긴 HTML을 클라이언트에 보내준다면 이 규칙을 잘 준수한다고 말할 수 있겠지만 대부분 저희가 설계하는 API는 프론트엔드와 백엔드 사이에서 JSON형식으로 데이터를 주고받고 프론트에서는 JSON을 이용하여 화면을 구성합니다. 그래서 저희가 설계하는 백엔드 API는 이 규칙을 위배하는 경우가 많습니다.
  • 일각에서는 어떠한 도메인(예:http://~/join)으로 어떠한 작업에 대한 요청(예:GET)을 보낼 수 있다라는 정보를 JSON에 담아서 보내고 프론트 단에서 JSON의 정보로 HTML을 만들어 사용자에게 보여주면 백엔드 서버에서도 이 규칙을 위배하지 않았다고 말하는 사람들도 있습니다.

줄여서 HATEOAS라고도 하지만 REST를 사랑하는 이들은 종종 이렇게 줄여부르는 걸 싫어하기도 합니다!

계층화(Layered System)

  • Layered System 제약 조건은 서버를 다중 계층으로 구성하여 사용할 수 있다는 것입니다.
  • 예를 들어 REST를 사용하면 서버 A에 API를 배포하고 서버 B에 데이터를 저장하며 서버 C에서 요청을 인증하는 계층형 시스템 아키텍처를 사용할 수 있습니다. 또한 자주 사용되지 않는 기능을 공유 중개 컴포넌트(shared intermediary)로 이동시킴으로써 컴포넌트를 단순화할 수 있습니다.
  • 클라이언트는 보통 대상 서버에 직접 연결되었는지, 또는 중간 서버를 통해 연결되었는지를 알 수 없습니다.
  • 중간 서버는 이런 중개 컴포넌트는 여러 네트워크, 프로세서 사이에서 서비스의 로드 밸런싱을 가능하게하여 시스템의 확장성을 향상시킬 수 있습니다.
  • Layered system의 주요한 단점으로는, 데이터의 처리에 대한 오버헤드와 지연(latency)이 심화되어, 사용자가 느끼는 성능이 감소된다는 것입니다. 이를 cache 제약조건을 지원하는 네트워크 기반 시스템에서 중개 컴포넌트에 공유 캐시를 둠으로써 성능 감소를 해결할 수 있습니다.

Code on demand (optional)

  • 자바 애플릿이나 자바스크립트의 형태로 코드를 다운로드하고 실행할 수 있도록 함으로써 서버가 클라이언트가 실행시킬 수 있는 로직을 전송하여 기능을 확장시킬 수 있다. 이는 클라이언트측에서 구현해야 할 기능을 감소시켜 클라이언트를 단순화시킬 수 있습니다.
  • 이 조건은 Optional로 꼭 지키지 않고 옵션처럼 사용할 수 있는 기능입니다.

REST에 대한 내 정리

  • REST는 API가 아니라 API를 디자인 하기 위한 패턴입니다.
  • REST는 API설계를 위한 스타일이지 HTTP에 종속된 건 아닙니다! HTTP에서 적용하기 쉬운 이유는 REST의 원칙들 중 다수가 HTTP로부터 영향을 많이 받았기 때문입니다.
  • 하지만 웹에서의 주요 프로토콜이 HTTP이기 때문에 웹개발자 입장에선 대부분의 REST API 설계를 HTTP 위에서 하게 되는 것 같습니다! 하지만 이도 REST가 HTTP에 종속되었다는 것은 아닙니다!!
  • 꼭 REST의 규칙들을 모두 지키는 REST API를 만드는 것이 모든 상황에서 좋냐는 물음에는 아니라고 말할 수 있을 것 같습니다. 이 모든 것을 지켜서 만드는 것이 모든 상황에서 효율적이라 할 수 없고 로이 필딩도 “시스템 전체를 통제할 수 있다고 생각한다면 REST를 따지느라 시간을 낭비하지 말라”라고 말하고 있습니다.
  • 하지만 REST의 조건을 지키지 못한 채로 REST API라고 부르는 것에는 문제가 있는 것 같습니다. 이 부분에 대해서는 로이 필딩이 많은 화를 내고 있습니다.. 번역을 통해 글을 봐서 그런지 어조가 좀 무서운 거 같아요..
  • 이 글을 쓰며 로이 필딩의 글을 많이 봐서 그런지 로이 필딩에 대한 언급이 상당히 많은 것 같네요.. 저도 깊은 내용이라 공부를 오래 하고 로이 필딩의 이름을 너무 많이 봐서 노이로제가 걸릴거 같기도 합니다..하하
  • 다음 포스트로는 REST API에 대해서 공부해보도록 하겠습니다!!
  • (정말 많이 공부하고 많이 썼다고 생각하는데 생각보다 포스트가 길지는 않네요.. 뭔가 섭섭합니다..😢)
profile
블로그 이전했습니다!! 👉 https://alswp006.github.io/

0개의 댓글