REST API에 대해 설명하기 전, API가 무엇인지 잠깐 훑고 가겠다.
클라이언트는 원하는 정보/기능에 접근하기 위해 일종의 명령 메뉴얼이 필요하다. 서버는 이 메뉴얼을 제공하는데, 이를 API(Application Programming Interface)라고 한다. 이 말이 잘 이해가 안간다면 아래 예시를 보자.
최근 장을 보러갔는데 무 가격때문에 놀랐던게 갑자기 생각나서 무를 예시로 들겠다. 요새 동물의숲 무트코인 마냥 현실 무값도 굉장히 올랐는데, 오늘 무 요리를 하기 위해 무를 사야한다고 가정해보자. 나의 전재산이 1000원밖에 없어서 무가 그보다 비싸면 살 수 없기 때문에 서버를 통해 데이터베이스(무 현재 가격)에 접근해 오늘 무를 살지 말지 결정하려고 한다.
그런데 서버한테 "님 오늘 무 얼마임?"라고 물어봐야 할지, "금일 무의 개당 시세는 얼마입니까?"라고 물어봐야 할지 모른다. 이 상황에서 API는 무 가격을 확인할 수 있는 올바른 방법을 지정해 준다. 서버에서 무 값을 확인하기 위해서 "오늘 무값 알려줘"라고 말해야 한다고 API가 정해줬다고 가정하면 나는 서버에 문장 그대로 물어보면 된다.
REST(Representational State Transfer) API는, 로이 필딩(엄청 유명한 컴퓨터 공학자)의 논문에서 처음 소개 되었다. REST API는 웹에서 사용되는 데이터/자원을 HTTP URI로 표현하고, HTTP 프로토콜을 통해 요청과 응답을 정의하는 방식을 말한다.
REST 성숙도 모델은 레너드 리처드슨(REST API 전문가)에 의하여 창시되었으며, 0-3단계가 있다. 좋은 REST API를 만들기 위해서는 이 모델을 참조하면 된다.
다음은 각 단계를 알아보자.
클라이언트와 서버의 request/response 과정에서 HTTP 프로토콜을 사용하기만 하면 0단계는 충족된다.
성숙도 모델의 0단계를 적용한 병원 예약 예시의 그래프다. 해당 예시는 3단계 까지 계속 쓰인다.
POST /appointmentService HTTP/1.1
[various other headers]
<openSlotRequest date = "2010-01-04" doctor = "mjones"/>
클라이언트(정보 요청자)는 mjones라는 의사에게 진찰을 받고싶어 한다.
클라이언트는 위 HTTP 메세지를 통해 예약 가능한 시간대 슬롯을 요청하고 있다.
/appointmentService라는 엔드포인트를 이용해 필요한 정보에 접근한다.
HTTP/1.1 200 OK
[various headers]
<openSlotList>
<slot start = "1400" end = "1450">
<doctor id = "mjones"/>
</slot>
<slot start = "1600" end = "1650">
<doctor id = "mjones"/>
</slot>
</openSlotList>
서버(응답자)는 예약 가능한 슬롯들을 XML 형식으로 리턴해주고 있다.
예시에서 XML을 사용하였을 뿐, 그 이외의 다른 형태의 정보(JSON 등)여도 상관없다.
HTTP/1.1 200 OK
[various headers]
<appointment>
<slot doctor = "mjones" start = "1400" end = "1450"/>
<patient id = "jsmith"/>
</appointment>
클라이언트 jsmith는 예약하고 싶은 슬롯을 골라서 정보를 보낸다.
HTTP/1.1 200 OK
[various headers]
<appointment>
<slot doctor = "mjones" start = "1400" end = "1450"/>
<patient id = "jsmith"/>
</appointment>
서버는 jsmith가 원하는 슬롯에 예약이 되었다고 응답한다.
개별 리소스와의 통신을 준수해야 한다. REST API는 웹상의 모든 데이터/자원을 HTTP URI로 표현하는데, 모든 자원은 특정 데이터/자원에 맞는 엔드포인트를 사용해야 하며 요청/전달되는 데이터/자원에 대한 정보를 응답으로 전달해야 한다.
이전 0단계 예시에서는 예약 슬롯의 요청과 슬롯을 골라 예약하는 과정 모두 /appointmentService라는 단일 엔드포인트를 사용하였다. 그러나 REST Maturity Model의 1단계에선 두 리소스에 접근하는 엔드포인트를 구분해야 한다.
POST /doctors/mjones HTTP/1.1
[various other headers]
<openSlotRequest date = "2010-01-04"/>
mjones라는 의사는 그 의사만의 리소스를 가지고 있으며, 0단계에서 모든 request에 동일한 엔드포인트를 사용했음과 대비, 엔드포인트도 '/doctors/mjones' 로 개별화 된다.
HTTP/1.1 200 OK
[various headers]
<openSlotList>
<slot id = "1234" doctor = "mjones" start = "1400" end = "1450"/>
<slot id = "5678" doctor = "mjones" start = "1600" end = "1650"/>
</openSlotList>
리턴되는 슬롯도 아이디가 부여되어 개별화 되어있는데 이 아이디는 밑 예시인 예약 요청 endpoint에 사용된다.
POST /slots/1234 HTTP/1.1
[various other headers]
<appointmentRequest>
<patient id = "jsmith"/>
</appointmentRequest>
역시 id가 1234인 슬롯을 예약하기 위해 그 슬롯만을 위한 엔드포인트인 '/slots/1234' 를 사용하고 있다.
HTTP/1.1 200 OK
[various headers]
<appointment>
<slot id = "1234" doctor = "mjones" start = "1400" end = "1450"/>
<patient id = "jsmith"/>
</appointment>
예약이 되었다는 응답을 주고 있다.
2단계에서는 HTTP 문법을 사용해야 한다. 이는 CRUD에 맞는 HTTP 메소드 사용이다.
0단계, 1단계 에서는 모든 요청에 POST를 사용했지만 2단계 에서는 실행하는 동작에 따라 다른 메소드를 사용한다.
GET /doctors/mjones/slots?date=20100104&status=open HTTP/1.1
Host: royalhope.nhs.uk
이전에는 정보 요청에도 POST 메소드를 사용하였지만, 이제는 정보를 요청(CRUD 중 READ)하는 동작에 맞게 GET 메소드를 쓰고 있다.
HTTP/1.1 200 OK
[various headers]
<openSlotList>
<slot id = "1234" doctor = "mjones" start = "1400" end = "1450"/>
<slot id = "5678" doctor = "mjones" start = "1600" end = "1650"/>
</openSlotList>
response는 이전 단계와 같다.
POST /slots/1234 HTTP/1.1
[various other headers]
<appointmentRequest>
<patient id = "jsmith"/>
</appointmentRequest>
예약을 요청하는 HTTP request는 이전과 같이 POST 메소드를 사용하고 있다. 슬롯의 예약 여부 정보를 생성(CRUD 중 CREATE) 해주어야 하기 때문이다.
HTTP/1.1 201 Created
Location: slots/1234/appointment
[various headers]
<appointment>
<slot id = "1234" doctor = "mjones" start = "1400" end = "1450"/>
<patient id = "jsmith"/>
</appointment>
예약이 되었다는 응답을 주고 있다. 여기서 201이 뜨는데, 이 HTTP 코드 속성에는 나중에 누군가 GET 메소드로 해당 정보를 읽어올 수 있게 위치 속성이 포함된다.
REST API Maturity Model의 마지막 단계인 3단계에서는 HATEOAS(Hypertext As The Engine Of Application State)라는 개념이 등장한다. 이 개념을 활용한 3단계 에서는 리턴되는 정보가 추가적인 URI를 포함해야만 한다.
GET /doctors/mjones/slots?date=20100104&status=open HTTP/1.1
Host: royalhope.nhs.uk
request는 2단계와 같다.
HTTP/1.1 200 OK
[various headers]
<openSlotList>
<slot id = "1234" doctor = "mjones" start = "1400" end = "1450">
<link rel = "/linkrels/slot/book"
uri = "/slots/1234"/>
</slot>
<slot id = "5678" doctor = "mjones" start = "1600" end = "1650">
<link rel = "/linkrels/slot/book"
uri = "/slots/5678"/>
</slot>
</openSlotList>
그러나 response에 새로운 것이 생겼다. 어떤 URI로 가야 해당 슬롯을 예약할수 있는지의 추가 정보를 담고 있다.
POST /slots/1234 HTTP/1.1
[various other headers]
<appointmentRequest>
<patient id = "jsmith"/>
</appointmentRequest>
레벨 2와 같다.
HTTP/1.1 201 Created
Location: http://royalhope.nhs.uk/slots/1234/appointment
[various headers]
<appointment>
<slot id = "1234" doctor = "mjones" start = "1400" end = "1450"/>
<patient id = "jsmith"/>
<link rel = "/linkrels/appointment/cancel"
uri = "/slots/1234/appointment"/>
<link rel = "/linkrels/appointment/addTest"
uri = "/slots/1234/appointment/tests"/>
<link rel = "self"
uri = "/slots/1234/appointment"/>
<link rel = "/linkrels/appointment/changeTime"
uri = "/doctors/mjones/slots?date=20100104&status=open"/>
<link rel = "/linkrels/appointment/updateContactInfo"
uri = "/patients/jsmith/contactInfo"/>
<link rel = "/linkrels/help"
uri = "/help/appointment"/>
</appointment>
슬롯 정보 response와 같이 이번 response로 추가 URI 정보를 담고있다. 예약 취소, 검사 추가, 시간 변경 등 리턴된 정보에서 파생될 수 있는 추가적인 action을 위한 URI가 있다.
출처: https://martinfowler.com/articles/richardsonMaturityModel.html
세상에나 ㄷㄷ
잘보고가욥 :D