REST API 이해와 설계 - #2 API 설계

조대협 님께서 블로그에 개제 해주신 내용을 보고 정리하였습니다. 


출처 : http://bcho.tistory.com/954




● REST API 디자인 가이드




◎ REST URI는 심플하고 직관적으로 만들자


REST API를 URI만 보고도, 직관적으로 이해할 수 있어야 한다. URI를 길게 만드는 것 보다, 최대 2 depth 정도로 간단하게


만드는 것이 이해하기 편하다.


      • /dogs
      • /dogs/1234

URI에 리소스명은 동사보다는 명사를 사용한다.

REST API는 리소스에 대해서 행동을 정의하는 형태를 사용한다. 예를 들어서

 POST /dogs


는 /dogs라는 리소스를 생성하라는 의미로, URL은 HTTP Method에 의해 CRUD의 대상이 되는 개체(명사)이어야 한다.


잘못된  예를 보면

      • HTTP POST : /getDogs
      • HTTP POST : /setDogsOwner

위의 예제는 행위를 HTTP POST로 정의하지 않고, get/set 등의 행위를 URL에 붙인 경우인데, 좋지 않은 예이다.

이보다는

      • HTTP GET : /dogs
      • HTTP POST : /dogs/{puppy}/owner/{terry}

를 사용하는 것이 좋다. 그리고 가급적이면 단수형 명사(/dogs) 보다는 복수형 명사(/dogs)를 사용하는 것이 의미상 

표현하기 더 좋다.


일반적으로 권고되는 디자인은 다음과 같다.

리소스 

POST 

GET 

PUT 

DELETE 

create

read

update 

delete 

 /dogs

새로운 dogs 등록 

dogs 목록을 리턴 

Bulk로 여러 dogs 정보를 업데이트 

모든 dogs 정보를 삭제 

/dogs/badduk 

에러 

baduk 이라는 이름의 

dogs 정보를 리턴 

baduk이라는 이름의 

dogs 정보를 업데이트 

baduk 이라는 이름의 

dogs 정보를 삭제 






◎ 리소스간의 관계를 표현하는 방법


REST 리소스 간에는 서로 연관관계가 있을 수 있다. 예를 들어 사용자가 소유하고 있는 디바이스 목록이나 사용자가 가지고 있는


강아지들 등이 예가 될 수가 있는데, 사용자 - 디바이스 또는 사용자 - 강아지 등과 같은 각각의 리소스 간의 관계를 표현하는 방법은


여러가지가 있다.



◎ Option 1. 서브 리소스로 표현하는 방법


예를 들어 사용자가 가지고 있는 핸드폰 디바이스 목록을  표현해 보면


      • /"리소스명"/"리소스 id"/"관계가 있는 다른 리소스명" 형태
      • HTTP GET : /users/{userid}/devices       예) /users/terry/devices

와 같이 /terry라는 사용자가 가지고 있는 디바이스 목록을 리턴하는 방법이 있다.


◎ Option 2. 서브 리소스에 관계를 명시하는 방법


만약에 관계의 명이 복잡하다면 관계명을 명시적으로 표현하는 방법이 있다. 


예를 들어 사용자가 "좋아하는" 디바이스 목록을 표현해보면


    • HTTP GET : /users/{userid}/likes/devices     예) /users/terry/likes/devices
는 terry라는 사용자가 좋아하는 디바이스 목록을 리턴하는 방식이다.

Option 1, 2 어떤 형태를 사용하더라도 문제는 없지만, Option 1의 경우 일반적으로 소유 "has"의 관계를

묵시적으로 표현할 때 좋으며, Option 2의 경우에는 관계의 명이 애매하거나 구체적인 표현이 필요할 때 사용한다.




● 에러처리


에러처리의 기본은 HTTP Response Code를 사용한 후, Response body에 error detail을 서술하는 것이 좋다.


대표적인 API 서비스들이 어떤 HTTP Response Code를 사용하는지를 살펴보면 다음과 같다.


구글의 gdata 서비스의 경우 10개, 넷플릭스의 경우 9개, Digg의 경우 8개의 Response Code를 사용한다.



◎ Google GData


200 201 304 400 401 403 404 409 410 500


◎ Netflix


200 201 304 400 401 403 404 412 500


◎ Digg


200 400 401 403 404 410 500 503



    • 200 Success - 성공
    • 400 Bad Request - field validation 실패시
    • 401 Unauthorized - API 인증, 인가 실패
    • 404 Not found - 해당 리소스가 없음
    • 500 Internal Server Error - 서버 에러

추가적인 HTTP Response Code에 대한 사용이 필요하면 HTTP Response Code 정의

http://en.wikipedia.org/wiki/Http_error_codes 문서를 참고.


다음으로 에러에는 에러 내용에 대한 디테일 내용을 http body에 정의해서, 상세한 에러의 원인을 전달하는 것이

디버깅에 유리하다.

Twillo의 Error Message 형식의 경우

      • HTTP Status Code : 401
      • {"status":"401","message":"Authenicate","code":"20003,"more
        info":"http://www.twillo.com/docs/errors/20003"}

와 같이 표현하는데, 에러 코드 번호와 해당 에러 코드 번호에 대한 Error dictionary link를 제공한다.

비단 API 뿐 아니라 잘 정의된 소프트웨어 제품의 경우에는 별도의 Error 번호에 대한 Dictionary를 제공한다.



● API 버전 관리


API 정의에서 중요한 것 중의 하나는 버전 관리이다. 이미 배포된 API의 경우에는 계속해서 서비스를 제공하면서, 


새로운 기능이 들어간 새로운 API를 배포할 때는 하위 호환성을 보장하면서 서비스를 제공해야 하기 때문에,


같은 API라도 버전에 따라 다른 기능을 제공하도록 하는 것이 필요하다.


조대협님께서는 다음의 형태로 정의하는 것을 권장한다.


    • {servicename}/{version}/{REST URL}
    • example) api.server.com/account/v2.0/groups

이는 서비스의 배포 모델과 관계가 있는데, 자바 애플리케이션의 경우, account.v1.0.war, account.v2.0.war와 같이 

다른 war로 각각 배포하여 버전별로 배포 바이너리를 관리할 수 있고, 앞단에 서비스 명을 별도의 URL로 뗴어 놓는 것은

향후 서비스가 확장되었을 경우에, account 서비스만 별도의 서버로 분리해서 배포하는 경우를 생각할 수 있다.

외부로 제공되는 URL은 api.server.com/account/v2.0/groups 로 하나의 서버를 가르키지만,

내부적으로 HAProxy 등의 reverse porxy를 이용해서 이런 URL을 맵필할 수 있는데, api.server.com/account/v2.0/groups를

내부적으로 account.server.com/v2.0/groups로 맵핑 하도록하면,  외부에 노출되는 URL 변경이 없이

향후 확장되었을때 서버를 물리적으로 분리해내기가 편리하다.



● 페이징









Designed by JB FACTORY