컴퓨터 공부/🎮 테크레터

🎮 [테크레터 1편] RESTful API 가 뭘까?

letzgorats 2023. 12. 22. 15:31

RESTful API 는 REST 스러운 API 입니다!

 

그렇다면, REST 란 무엇일까요?

알아보기 전에, 먼저 REST의 등장 배경을 살펴봅시다. 


✅ 배경

30년 전, World Wide Web(WWW) 의 등장으로 정보 공유/접근이 굉장히 쉬워졌습니다.

하지만, 기존 www는 다음과 같은 문제점을 가지고 있었습니다.

 

문제 1) 클라이언트와 서버 간 결합도가 높다!

사람들이 웹상에서 통신을 할 때, 각자 다른 프로토콜과 데이터 형식을 사용한다고 가정해봅시다.(여기서 프로토콜은 쉽게 말해서 통신 규칙 이라고 이해하시면 됩니다.) 이 때, 통신 대상이 누구냐에 따라서 사용해야 되는 프로토콜과 데이터 형식이 달라지게 됩니다.

 

예를 들어, 이런 상황이 발생할 수 있습니다. 

정엽이가 웹 서버를 만들고 싶은데, 알루 서버에서 제공하는 데이터가 꼭 필요해서 이런 고민을 합니다.

 

 

이처럼, 서버의 변경이 클라이언트에게 심각한 영향을 끼치게 된 것이죠.

기존의 www는 서버와 클라이언트간의 결합도가 너무 높았고, 표준이 되는 통신 형식이 존재하지 않으니까 이런 문제가 많이 발생하게 됐습니다.

 

문제 2) 자원의 표현 및 상태 관리가 어렵다!

 

똑같은 회원 정보 생성이라는 기능을 봤는데,

  • /new-user -> 회원정보생성
  • /new/user -> 회원정보생성

A라는 사람은 /new-user 라는 URI 로 설계를 했고, B라는 사람은 /new/user 라는 URI 로 설계를 했다고 가정해봅시다.

 

이처럼, 자원을 어떻게 표현할지, 어떻게 관리할지 표준이 부재했습니다! → 이는 높은 복잡도로 이어졌습니다.

 

사실, 기존 웹은 HTML 이나 이미지 파일 같은 정적 자원을 전송하기 위해서 사용되었습니다.

그러나, 사용하는 사람이 점점 더 많아지고 한 페이지 안의 정보가 많아지고 복잡해지다보니, 자원 관리가 어려워졌습니다.

 

→ 조그마한 자원이 변경되더라도, 페이지 전체를 다시 요청해야하는 문제가 생겼습니다.

→ 즉, 네트워크 성능 문제로 이어지게 된 셈이죠.

 

다시말해, 단순성, 일반성, 관심사의 분리라는 견고한 원칙에 기반했음에도

 

1. 클라이언트와 서버 간의 결합도가 높다.

2. 자원 관리가 어렵다

 

라는 단점이 존재했었습니다!

..

...

....

이 때, 로이 필딩 좌가 나타났습니다!

로이 필딩

흠...기존의 웹을 손상시키지 않으면서(HTTP 호환성을 유지하면서)
웹을 보다 잘 사용할 수 있는 방법이 없을까?

 

이런 고민 끝에 등장한 것이 바로 REST 입니다.

REST  Respresentational State Transfer 의 약자로

  • 분산 하이퍼미디어 시스템을 위한 아키텍처 스타일 입니다.

말이 좀 어려운데, 대표적인 분산 하이퍼미디어 시스템의 예로는 이 있습니다.

아키텍처 스타일이란? 제약조건의 집합을 의미합니다.

  • 즉, 간단히 이야기하면 REST는 웹을 위한 제약조건의 집합입니다.

< REST의 제약조건 6가지 >

  1. 클라이언트 - 서버 구조
  2. 무상태성
  3. 캐시가능성
  4. 계층형 시스템
  5. 주문형 코드(optional)
  6. 균일한 인터페이스

인데, 이 6가지 제약조건 중 optional 한 제약조건을 제외하고 모두를 만족해야 "REST 하다 즉, RESTful 하다" 라고 말할 수 있습니다.

그리고, 여섯 번째 제약조건인 "균일한 인터페이스"는 REST의 핵심이 되는 내용이자 가장 중요하면서도 지키기 어려운 제약조건입니다.

 

그럼, 이런 제약 조건들을 하나하나 살펴보도록 하겠습니다.


✅ REST의 제약조건 6가지

1. 클라이언트 - 서버 구조

: (클라이언트는 요청을 발생)시키고, (서버는 요청에 대해 반응)합니다!

 

이렇게 관심사의 분리를 통해, 클라이언트는 UI의 이식성에 집중하게 되고 서버는 확장성(scalbility)에만 집중할 수 있게 됩니다.

서버는 단순히 데이터만 전달하면 끝!  ↔ 클라이언트는 안드로이드가 됐든 IOS 가 됐든 데이터를 받아서 원하는 UI 로 구성하면 끝!

 

2. 무상태성(stateless)

: 요청은 상태를 가지지 않는다는 제약조건

: 즉, 각각의 요청은 독립적이고 필요한 모든 정보를 제공해야 합니다.

 

: 쉽게 말해, 서버는 클라이언트가 이전에 무슨 요청을 보냈는지 모릅니다!

클라이언트가 서버에게 "ID는 '알루'이고 장바구니 정보를 줘!" 라고 요청을 하면, 서버는 정상 응답을 합니다.

그런데, 몇 분 뒤에 클라이언트가 아이디 정보를 빼고 그냥 장바구니 정보를 달라고 요청하면, 서버는 "누구 장바구니요?" 라고 응답합니다.

 

즉, 서버는 클라이언트가 누군지도 모르기 때문에 클라이언트는 요청을 보낼 때, 모든 정보를 포함해서 보내야 합니다.

 

3. 캐시 가능성

: 서버는 자원이 캐시 가능한지 명시해야 한다는 제약조건

클라이언트가 서버에게 "ID는 '알루'이고 장바구니 정보를 줘!" 라고 요청을 하면, 서버는 정상 응답을 하면서 "그리고, 너 이거 캐싱해도 돼" 라고 마킹을 해줍니다.

 

그러면, 클라이언트는 일정 시간 내에 다시 똑같은 요청을 보내려고 할 때 장바구니 정보가 있다면, 요청을 생략할 수가 있게 되는 것이죠.

 

4. 계층형 시스템

: 계층형 시스템을 적용해야 한다는 제약조건

만약에, 클라이언트가 "A,B,C 세 가지 기능을 모두 수행해라" 라고 서버에게 메시지를 보낸다고 가정해봅시다.

 

이 때, 서버가 (인증서버, API 서버, DB 서버) 처럼 계층형 시스템으로 구성이 되어있다면, 이 A, B, C 세가지 기능을 수행한다는 것을 각각의 책임에 맞게 메시지를 해석할 수 있기 때문에 단순성과 확장성이 굉장히 유리합니다.

 

5. 주문형 코드(Optional)

: 클라이언트가 '필요에 의해' 기능을 확장할 수 있도록 해야한다는 제약조건

 

클라이언트가 "앞으로 A라는 기능이 필요할 것 같아"라고 메시지를 보내면, 서버는 A를 실행할 수 있는 파일(코드)를 전달합니다.

그러면, 이후에 클라이언트가 똑같은 요청을 보내려고 할 때, 단순히 저장된 파일을 실행하기만 하면 돼서 요청을 필요가 없어집니다.

 

주문형 코드의 대표적인 예시가 바로 "플러그인" 입니다.

클라이언트의 단순성을 향상시키는 이점이 존재하지만, 시스템 전체적으로 적용되었을 때 오히려 성능이 안 좋아지는 이슈가 발생할 수 있기 떄문에 optional 한 제약조건입니다.

 

 

앞서말한 제약조건들은 HTTP 프로토콜을 사용하게 되면, 어느 정도 쉽게 만족할 수 있습니다.

하지만, 이제부터 살펴볼 "균일한 인터페이스" 같은 경우 제대로 신경쓰지 않으면 쉽게 만족할 수가 없습니다.

 

6.🚨균일한 인터페이스🚨

: 개발을 할 때, 클라이언트와 맞닿아 있는 부분 (Http Request, Http Response 등) 을 쉽고 일반적으로 설계하라는 제약조건

 

이 균일한 인터페이스는 또 한번 하위의 4가지 제약조건으로 분류됩니다.

 

6-1. 자원의 식별

: 클라이언트와 서버 사이의 상호작용에서 고유하게 자원을 식별할 수 있어야 한다는 제약조건

 

예를 들어, 아래 API 에서 

api

두 방식 모두 고유한 product에 접근할 수 있다는 것을 보장해야 합니다.

 

6-2. 표현을 통한 자원의 조작

: 여기서 표현이란? 메타데이터 + 데이터이면서, 자원의 특정 상태를 의미합니다.

: 이러한 표현을 통해서 자원을 조작해야 한다는 제약조건

 

예시를 통해 살펴봅시다.

이름은 "알루"이고 나이는 "10살"인 품종이 "닥스훈트"인 상태를 가지는 애완동물을 만들고 싶으면, 아래와 같이 메시지를 보낼 수 있겠습니다.

이 메시지에서 본문 데이터는 name(이름)과 age(나이), species(품종) 입니다.

메타데이터 + 데이터 = 표현

본문 데이터인 name과 age, species 등과 Content-Type 같은 header 메타 데이터를 통틀어서 "표현" 이라 일컬을 수 있고,

이러한 표현을 이통해서 자원을 조작해야 합니다.

 

6-3. 자기서술적인 메시지

: 자원의 표현은 메시지를 처리하기에 충분한 정보를 제공해야 합니다.

 

: 앞서 말한 첫 번째, 두 번째 제약조건은 어느 정도 쉽게 만족할 수 있습니다.

: 하지만, 세 번째 이번 제약 조건은 다음에 설명할 HATEOAS 와 함께 가장 지키기 어려운 제약 조건 중 하나입니다.

 

자기서술적인 메시지는 자원의 표현은 자기서술적이어야 한다. 

즉, "메시지를 처리하기에 충분한 정보를 제공해야 한다" 는 의미입니다.

 

좀 전의 예시를 다시 살펴봅시다.

해당 표현은 메시지를 처리하기에 충분한 정보를 제공한다고 생각하시나요? → NO!

위와 같은 구조는 개발을 할 때, 흔히 볼 수 있는 구조이지만, 사실 자기서술적인 메시지를 잘 만족하지 않습니다.

 

과연, 이 메시지를 누구든지 이해할 수 있을까요? 저쪽 프랑스 사람이나 심지어 기계가 보고 이해할 수 있을까요?

 

대체, 어떤 것이 자기서술적인 메시지 일까요?

→ 자기서술적인 메시지를 만족하는 대표적인 예시로는 HTML 이 존재합니다.

HTML 은 명세가 존재하는데, 명세가 존재한다는 것은? 해당 메세지를 해석하기 위한 방법이 존재한다는 뜻입니다.

<html>
    ...
    <a href = " "></a>
    ...
</html>

 

만약, 해당 메시지에서 <a> 태그에 대한 의미를 모른다면, HTML "명세"를 찾아가 알아볼 수 있습니다.

즉, 이 메시지 하나로 누구든지 해석할 수 있는 상태가 되는 것입니다!

 

그러면, JSON 메시지는... 자기 서술적일 수 없을까요?  NO!

JSON도 자기서술적일 수 있는데, 총 2가지 방법이 존재합니다!

 

1) IANA 기관에서 커스텀 media type 등록하기

"name은 이름이고, age는 나이이고, species는 종"이라는 명세를 정의해 alooCoding-json 이라는

커스텀 mediaType을 등록해줄 수 있습니다.

 

2) 메시지 헤더에 명세가 포함된 링크 등록하기

해당 링크에 name, age, species의 명세를 담아 명세를 만들어 링크로 등록할 수 있습니다.

 

이렇게, 우리가 만든 메시지들을 설명할 수 있는 "명세"를 만들어 어떤 방식으로든 메시지들에 적용해서 자기서술적인 메시지를 만족할 수 있는 것입니다.

 

6-4. HATEOAS

: HATEOS란, Hypermedia As The Engine Of Application State 의 약자입니다.

: 클라이언트는 서버와 상호작용하면서 하이퍼링크를 통해 동적으로 모든 다른 리소스에 접근할 수 있어야 한다는 제약조건

 

한 번 예시를 살펴보겠습니다.

HATEOS 를 만족하는 예시로는 또 HTML 이 있습니다.

<html>
    ...
    <a href = "/aloo">링크1</a>
    <a href = "/coding">링크2</a>
    ...
</html>

 

HTML 의 경우, a 태그에 하이퍼링크가 나와있고 이 하이퍼링크를 통해 다른 리소스에 접근이 가능합니다. 

즉, 클라이언트가 어플리케이션의 상태를 동적으로 변경할 수 있으므로 HATEOAS 를 만족한다고 할 수 있습니다.

 

그렇다면, JSON 은 어떨까요?

위와 같은 JSON 에서는 name 이 '알루'이고, age가 10살이고, species 가 'dachshund' 라는 정보만 나타낼 뿐, 클라이언트가 다른 상태로 변경할 수 있는 방법이 존재하지 않습니다.

 

이를 HATEOAS를 만족하게 하려면 어떻게 해야 할까요?

 

첫 번째 방법으로는 Location 헤더에 hyperlink를 추가해줌으로써 만족시켜줄 수 있습니다.

자원을 생성하고 나서 응답코드로 "201 created" 등을 던져주게 되는데요, 그 때, 생성된 자원의 위치를 URI로 넘겨줄 수 있습니다.

Location에 자원이 생성된 hyperlink를 넣어줌으로써 HATEOAS 만족

 

즉, 자원을 생성했을 때 Location 헤더에 생성된 자원의 위치를 넣어준다면, HATEOAS 를 만족합니다. 

 

두 번째 방법으로는 헤더가 아닌 데이터로 링크를 넘겨주는 방식입니다.

데이터로 link를 넘겨줌으로써 HATEOAS 만족

 

이 방법은 말그대로 데이터에 링크를 추가해줘서 HATEOS 를 만족시켜줄 수 있습니다.

결국, 이러한 링크들을 추가함으로써 클라이언트가 동적으로 상태를 변경할 수 있게 하여 HATEOAS를 만족할 수 있습니다.


✅  정리

  • World Wide Web(WWW) 의 등장으로 폭발적인 사용량 증가로 인해 몇 가지 문제점이 생겨나게 되었음.
  • 이에 대한 해결방법으로 REST가 등장하게 되었음.
  • REST란, 제약조건의 집합으로서 optional 한 제약조건을 제외하고 5가지 이상의 제약조건을 모두 만족하면 RESTful 하다고 했음.
    • 1. 클라이언트-서버 구조 , 2. 무상태성, 3. 캐시 가능성, 4. 계층형 시스템, 5. 주문형 코드(optional), 6. 균일한 인터페이스
  • 6가지 제약조건 중, 가장 지키기 어려운 부분은 균일한 인터페이스였음.

✅  결론

- 우리가 만드는 API 는 RESTful 한가요? 정말 RESTful 이기 위한 제약조건을 모두 만족하고 있나요? → I don't thinks so.

- 그러면 항상 모든 RESTful 한게 좋은걸까요?

    - 모든 응답마다 명세를 만들어 자기서술적으로 만들어야 할까요?

    - 모든 응답마다 링크를 걸어서 HATEOAS를 만족하게 해야할까요?

→ No, You don't have to do that.

 

REST는 중요한 개념이지만, 실제 일반 기업의 API 에서 적용하기에는 복잡도가 매우 증가하고, 개발 비용 대비효과가 나오지 않아 거의 지켜지지 않는다고 합니다. 

실제로는 대부분의 RESTful API라고 불리는 것들이 완전히 REST를 따르지 않는 경우가 많습니다.

엄연히 따지면, HTTP API 라고 불러야 합니다.

 

즉, 실무에서는 완전히 RESTful 한 API를 만들기는 현실적으로 어렵다는 뜻입니다.

그러면, 언제 지키면 좋을까요?

 

REST 의 핵심은 "클라이언트와 서버 간의 결합도를 낮춰 독립적인 진화를 할 수 있게 하는 것" 입니다.

여기서 말하는 독립적인 진화란 서버와 클라이언트 간의 상호작용에서 변경의 영향을 최소화하고 유연성을 제공하기 위한 노력을 의미합니다.

 

독립적인 진화에 만족하는 대표적인 예시로는 웹과 웹브라우저가 있습니다.

우리가 웹페이지를 변경한다고 해서 웹브라우저를 업데이트할 필요는 없고, 반대로 웹브라우저를 변경한다고 해서 웹페이지를 업데이트할 필요가 없죠?

 

즉, 우리의 비즈니스 및 상황에 맞게 판단을 해서 사용하면 될 것 같습니다.

우리의 API를 RESEful 하게 만들지 고민이 된다면..!

우리의 서비스가 완전히 REST 했을 때, 기대효과는 어느정도인지 스스로 질문을 한 번 던져보는 것은 어떨까요?

 

끝으로, Roy T. fielding 님 께서는 다음과 같이 말한 바가 있습니다.

로이필딩 선생님의 띵언


[참고자료]

- 그런 REST API 로 괜찮은가(이용준)

- Architectural Styles and the Design of Network-based Software Architectures(Roy Fielding)

- restfulapi.net

반응형

'컴퓨터 공부 > 🎮 테크레터' 카테고리의 다른 글

🎮 [테크레터 2편] 인덱스 Index ?  (0) 2024.01.04