728x90

서버 개발을 하면서 REST API를 많이 접해볼 수 있습니다.
오늘은 이 REST가 무엇이며 일반 API와 REST API는 어떤 차이점을 가지고 있는지 알아보도록 하겠습니다.

REST란?

우선 REST API에 대해 알려면 REST가 무엇인지부터 알아야 합니다.

REST의 FullName은 REpresentational State Transfer인데, 직역하자면 '대표 상태 전송'이라고 해석할 수 있습니다.

REST는 HTTP프로토콜을 사용하며 분산형 하이퍼미디어 시스템의 아키텍처 스타일입니다. 

더보기

분산 하이퍼미디어 시스템(distributed hypermedia systems)이란?

여러 대의 컴퓨터나 네트워크로 구성된 시스템에서 하이퍼 미디어를 관리하고 제공하는 시스템

 

하이퍼미디어는 텍스트, 그래픽, 오디오, 비디오 등 다양한 멀티미디어 자료를 연결하여 구성한 것을 의미합니다.

즉 시스템 간 정보를 주고받는 시스템을 구축할 때 적용하는 아키텍처 스타일이라고 쉽게 표현할 수 있습니다.

이는 프로토콜이나 표준이 아니고 네트워크를 통해 애플리케이션을 느슨하게 설계하기 위한 지침으로 굳이 안 지켜도 됩니다.

다만 REST스타일을 벗어나게 된다면 REST API가 일반 API가 될 뿐입니다.

 

REST 구성

REST는  HTTP를 사용한 아키텍처 스타일이다 보니 HTTP에서 제공하는 자원들을 활용합니다.

1. 자원 - HTTP URL

REST에서 URL은 어디로 갈 것인지 혹은 어떤 정보를 가지고 있는지 즉 정보의 자원을 명시합니다.

즉 URL에는 행위에 관련된 표현이 들어가는 것은 부적절하며, 명사가 들어가는 것이 좋습니다.

2. 행위 - HTTP Method

REST는 HTTP Method로 어떤 행위를 할 것인지를 표현합니다.

행위는 보통 5가지를 사용하며, 이 행위에 대한 것은 아래 표로 정리해 보았습니다.

Method Action
GET 리소스를 조회
POST 리소스 생성
PUT 리소스 수정
PATCH 리소스 부분 수정
DELETE 리소스 삭제

3. 표현 - HTTP Message Pay Load

통신에서 반환된 리소스를 반환하며 리소스는 JSON or XML or HTML 등의 타입을 가집니다.

이때 통신 상태에 대한 HTTP Status가 반환되는데 코드에 대한 의미는 다음과 같습니다.

Code Description
1XX 서버가 요청을 받았으니 클라이언트는 작업을 계속 진행할 것을 의미
2XX 요청을 완료하였음을 의미
3XX URL이 변경되었거나 다른 URL을 호출 할경우
4XX Client에서 서버를 호출할 때 잘못된 호출을 할 경우
5XX 서버에서 요청을 처리 혹은 서버 자체가 잘못 되었을 경우

REST의 제약 조건

REST를 적용하려면 몇 가지 조건이 지켜져야 RESTful하다 할 수 있는데 어떤 조건들이 있는지 알아보겠습니다.

1. Client-Server

클라이언트와 서버의 완전 분리입니다.

클라이언트와 서버를 분리하여 개발을 함으로써 서로 변경사항에 대해 영향을 주지 않기 위함입니다.

 

클라이언트는 URI정보를 통해 서버를 호출할 수 있어야 하며,

서버는 HTTP를 통해 들어온 요청에 대해 데이터를 전달할 수 있습니다.

2. Stateless

Stateless 즉 무상태는 서버에서 클라이언트의 상태에 대한 정보를 가지고 있지 않다는 의미입니다.

이는 Stateless의 반대인 Stateful을 보면 더욱 쉽게 이해할 수 있습니다.

 

Stateful은 서버가 클라이언트의 상태를 가지고 있다는 것을 의미하며, 이는 클라이언트와 서버의 통신은 연결되어 있어 작업을 할 때 서버에서 클라이언트 상태를 보고 작업을 하는 것입니다. 이럴 경우 통신 중이던 서버에 장애가 생길 경우  클라이언트는 그동안 서버에 저장된 상태정보를 유실하게 되어 처음부터 통신을 시작해야 하는 경우가 생깁니다.

 

Stateless는 서버가 클라이언트의 상태를 가지고 있지 않아 클라이언트가 서버를 호출할 때마다 필요한 상태 정보들을 같이 넘겨줘야 한다는 번거로움이 존재합니다. 하지만 위의 경우처럼 서버가 장애가 생겼을 때 같은 기능을 하는 다른 서버가 해당 작업을 이어받아 처리할 수 있게 할 수 있습니다. 즉 서버 확장에 대해 Stateful에 비해 자유롭다고 볼 수 있습니다.

3. Cache

서버에서 응답을 줄 때 해당 리소스의 캐싱 가능 여부와 응답 캐싱기간을 알려주는 정보가 포함되어있어야 하며, 캐싱할 수 있어야 합니다.

이는 클라이언트와 서버의 성능을 향상하는데 도움을 줍니다.

4. Uniform Interface

Uniform Interface는 REST API인가?를 결정하는 가장 중요한데, 이는 클라이언트와 서버의 통신이 일관되고 표준화된 방식이 되도록 유도하는 요소입니다.

 

Uniform Interface는 4가지로 구성되어 있습니다.

- Identification of resources

각 리소스들은 고유한 URI를 가져 식별되어야 합니다.

쉽게 말하면 API를 생성할 때 URI는 고유하게 식별되어 위치를 특정할 수 있어야 한다는 의미입니다.

 

- Manipulation of resources though represenations

이것을 이해하기 위해선 우리는 우선 Represenation에 대해 알아야합니다.

GET http://localhost:8080/helth
Accept:text/plain
Accept-Language:en-US;q=0.8,en;q=0.7

위와 같이 서버가 잘 작동하고 있는지 확인하는 API를 호출한다고 가정해보겠습니다.

그럼 우리가 전달받는 리소스는 "OK"라는 데이터를 받을 수 있을 것 입니다.

하지만 이는 잘못된 설명이였습니다.

 

그 이유는 "OK"라는 것은 리소스가 아닌 represenation data이기 때문입니다.

왜 리소스가 아니냐면 우리는 "OK"라는 데이터를 응답으로 받았지만 여기서 리소스는 "확인을 위한 의미를 담은 문서"이기 때문입니다.

즉 represenation data는 'text/plain' 타입의 영어로 된 데이터가 되는 것 입니다.

 

그리하여 클라이언트는 서버에 'text/palin'을 표현해주길 원하면 텍스트 데이터를, 'text/html'을 표현해주길 원하면 html로 된 데이터를 전달 받을 수 있는 것 입니다. ( 물론 여러 표현방법에 대한 API는 서버에 구현이 되어있어야 합니다 안할경우 406error!! )

 

그럼 Manipulation of resources though represenations는 무슨 의미인가?

요청하는 URI는 동일하지만 표현방법에 따라 응답할때 전달하는 represenation Data 가 둘이상 지원된다는 의미입니다.

즉 URI가 같더라도 원하는 Represenation에 따라 여러 데이터를 응답 받을 수 있다로 설명이 가능할 것 같습니다. 

 

- Self-descrive messages

각 응답과 요청은 스스로 설명이 가능해야 합니다.

이게 무슨 의미냐면, 응답받은 데이터들이 JSON으로 왔다고 가정해 보겠습니다.

{
    "name": "hong gil dong",
    "description": "This is a living thing."
}

위와 같은 리소스를 응답으로 받았다면, 우리는 저 name이 사람이름인지 동물이름인지 알 수 있는 방법이 없을 것입니다.

이럴 때 응답만을 보고 저게 사람이름인지 동물이름인지 알 수 있게 자체적으로 설명이 있어야 한다는 뜻입니다.

 

Spring REST Docs와 같은 프레임워크를 활용하여 응답 리소스에 Doc의 link를 실어 보내주는 방법으로 해결을 해야합니다.

 

- Hypermedia as the engine of application state ( HATEOAS )

클라이언트는 서버로부터 전송받는 응답으로 다음 가능한 행위를 결정할 수 있어야합니다.

이게 무슨 뜻인가!

이전에 우리는 이름과 설명을 응답으로 받았습니다.

여기에 설정을 붙여보겠습니다.

우리가 만약 사람들 관리 사이트에서 유저 상세 화면을 개발하고 있다고 가정을 해보겠습니다.

이때 우리는 기본적으로 해당 유저에 대한 정보들을 가져오게 될 것 입니다.

{
    "name": "hong gil dong",
    "age": 27,
    "phoneNumber": "010-0000-0000"
}

이제 우리는 저 정보들을 가지고 개발을 하게 될 것입니다.

하지만 우리가 페이지 내에서 다음 사람을 보고 싶다거나 할 때 어떤 행위를 해야할 지 위 응답에는 포함되어있지 않습니다.

 

{
    "name": "hong gil dong",
    "age": 27,
    "phoneNumber": "010-0000-0000",
    "links": [
    	{
        	"rel": "self",
            	"href": "http://localhost:8080/user/2"
        },
    	{
        	"rel": "befor",
            	"href": "http://localhost:8080/user/1"
        },
    	{
        	"rel": "after",
            	"href": "http://localhost:8080/user/3"
        }
    ]
}

위와 같이 Hateoas를 적용한다면 이전 유저를 조회하려면 어떤 행위를 해야하는지, 이후 유저를 조회하려면 어떻게 해야하는지에 대한 정보들이 응답에 포함되어있습니다.

 

이로인해 클라이언트는 다른 정보 없이 응답받은 정보들 속에서 다음 행위를 결정할 수 있게 되는 것 입니다.

5. Layered System

클라이언트나 서버 사이 중간계층들을 둘 수 있도록 확장성을 열어 놓은 것을 의미합니다.

미들웨어, 프록시, 게이트웨이, 캐시 서버, 로드 밸런서 등이 이에 포함되며, 이렇게 중간계층이 추가된다 하더라도 클라이언트와 서버의 상호 작용에는 영향이 없어야합니다.

 

6. Code-On-Demand ( Optional )

REST 조건이긴하지만 필수 제약 조건은 아닙니다.

클라이언트가 서버에 코드를 요청시 서버는 클라이언트에서 실행될 소프트웨어 코드를 보내는 것이라 할 수 있습니다.

Java applets와 javaScript등이 있습니다. 

REST API

위와 같이 REST의 조건들을 지켜 API를 개발하였을 경우 이를 REST API라고 하며 이러한 REST API들로 개발된 웹 서비스를 'RESTful 하다' 라고 표현할 수 있습니다.

 

여러가지 장단점이 있는데, 

 

REST가 표준이 존재하지 않고 아키텍처 스타일이다보니 발생하는 장단점이 크다고 생각합니다.

장점은 위에서 계속 나왔듯이 확장성과 자율성이 뛰어난 API를 구축할 수 있다로 볼 수 있고,

단점은 너무 자율성이 높고 조건들이 많다보니 지켜지기 쉽지 않다고 볼 수 있습니다.

 

마치며

개인적으로 1, 2, 3, 5번은 HTTP API를 개발하면서 크게 신경쓰지 않아도 지켜지는 조건들이라고 생각합니다.

다만 4번의 조건들이 신경쓸 부분들이 많은 만큼 만약 REST API를 만들고 싶다면 조건들을 세심히 따져보시기 바랍니다.

 

REST API는 표준이 정해져 있지 않지만 조건들이 존재하는 만큼 어느정도 커스텀은 괜찮다고 보지만, 조건이 맞지 않다면 그냥 API개발했구나 생각하시면 될 것 같습니다. ( 제가 그랬습니다 ㅎㅎ )  


 참조

https://ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm

https://blog.npcode.com/2017/04/03/rest%EC%9D%98-representation%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80/

728x90

+ Recent posts