본문 바로가기
IT/java

Restful API

by 허브큐 2017. 12. 23.

 

RESTful API

REST는 HTTP 메소드와 URI 사용 등의 웹 표준을 준수하는 아키텍처 스타일로 다음과 같은 기본 철학을 가지고 있다.
    • 모든 리소스를 URI로 구별할 수 있다
    • 모든 리소스는 복수의 형태로 나타낼 수 있다
    • 모든 리소스는 HTTP 표준 메서드를 이용하여 접근/수정/생성/삭제할 수 있다
    • 서버에는 어떠한 상태 정보도 갖고 있지 않다

 

리차드슨 성숙도 모델 (RMM, Richardson Maturity Model)

 

레너드 리차드슨이 고안한 모델이다. REST를 리소스, 메서드, 하이퍼미디어 등의 용어를 사용해 알기 쉽게 설명한 모델로서 HTTp를 전송 계층의 관점에서 바라보는 것으로 시작한다.

 

레벨0 : 원격 프로시저 호출

일반 XML 데이터를 SOAP이나 XML-RPC 등으로 전송한다. POST 메서드만 사용하며, 서비스 간에 단일 POST 메서드로 XML 데이터를 교환한다. 초창기 SOA 애플리케이션 제작 시 흔히 사용된 방식이다.

레벨1 : REST 리소스

 

함수에 파라미터를 넘기는 대신 REST URI를 이용한다. 레벨 0처럼 POST 메서드 하나밖에 사용하지 않지만, POST 메서드로 서비스 간 통신을 하면서 복잡한 기능을 여러 리소스로 분산시킨다는 점에서 한 단계 발전된 형태라고 볼 수 있다.

 

레벨2 : 추가 HTTP 메서드

 

레벨2는 POST 이외에 GET, HEAD, DELETE, PUT 메서드를 추가적으로 사용한다. HTTP 요청시 여러 메소드를 사용하여 다양한 리소스를 제공할 수 있다는 점에서 REST의 진정한 유스 케이스라 할 수 있다.

 

레벨3 : HATEOAS

 

애플리케이션 상태 엔진으로써의 하이퍼미디어(HATEOAS, Hypermedia as the Engine of  Application State)는 리차드슨 성숙도 모델의 가장 성숙한 단계로서, 요청에 대한 하이퍼미디어 응답 속에 클라이언트가 다음에 취해야 할 액션에 관한 상태 정보가 담겨 있다. 레벨 3는 발견 가능성(Discoverability)이 높고, 응답 자체에 대한 필요한 내용이 고스란히 담겨 있다. 리소스뿐만 ㅇ아니라 그 이상의 부가적인 정보까지 나타낸다는 점에서 HATEOAS가 진정한 REST냐 하는 문제는 아직도 논란의 여지가 있다.

 

 

 

 


 

안전과 멱등성

* 멱등성 - 연산을 여러 번 적용하더라도 결과가 달라지지 않는 성질을 의미한다.

안전한 메서드(Safe methods)

  • 안전한 메서드란 서버 측의 상태 정보를 변경하지 않는 메서드를 가리킨다. (예: GET v1/coffees/orders/1234)
  • GET, HEAD와 같은 안전한 메서드는 캐시가 가능하다. 
  • PUT, POST, DELETE 메서드는 서버 리소스를 생성 또는 변경하므로 안전하지 않다. 

멱등한 메서드(Idempotent methods)

  • 멱등한 메소드란 몇 번을 호출되더라도 동일한 결과를 리턴하는 메서드를 말한다.
  • 안전한 메소드(Safe methods)란 서버 측의 상태 정보를 변경하지 않는 메소드를 가리킨다. (예: GET v1/coffees/orders/1234)
  • GET 메소드는 여러 번 호출해도 타킷 리소스는 동일한 응답을 하므로, PUT 메소드는 동일한 리소슷 업데이트하고 이후에도 그 결과가 달라지지 않으므로 멱등하다.
  • POST는 복수 호출 시 각기 다른 결과가 리턴되거나 새로운 리소스가 계속 만들어질 수 있으므로 멱등하지 않다.
  • DELETE는 처음에 리소스가 삭제되면 더 이상 존재하지 않고 여러 번 호출해도 결과가 달라지지 않기에 멱등하다.

 


 

 

RESTful 서비스의 설계 원칙

  • 어떤 명사(Nouns)로 리소스를 나타낼지 정한다.
  • 리소스 메소드 결정
    • CRUD에 해당하는 여러 가지 HTTP 메서드를 사용한다.
  • 리소스 표현형 (Representation) 결정
    • JSON, XML, HTML, 일반 텍스트 중 어떻게 리소스를 표현할지 선택한다.
  • JAX-RS API 기반 RESTful 서비스 구현
    • API 구현은 JAX-RS명세에 따라야 한다.
  • RESTful 서비스 배포
    • Tomcat과 같은 애플리케이션 컨테이너에 서비스를 배포한다.
  • RESTful 서비스 테스팅
    • 클라이언트 API를 작성하여 서비스를 테스트 또는 curl 및 브라우저 기바늬 툴로 REST 요청을 테스트한다.

리소스 URI 결정

모든 RESTful 리소스는 URI로 식별된다. REST가 확장성이 좋다고 하는 것은 이 때문이다.
 
 URI 설명 
 /v1/library/books 도서관 장서 전체 
 /v1/library/books/isbn/12345678 ISBN이 '12345678'인 도서 
 /v1/coffees 커피숍에서 판매하는 커피 전체 
 /v1/coffees/orders 커피숍에서 고객이 주문한 커피 
 /v1/coffees/orders/123 주문번호가 '123'인 주문 정보 
 /v1/users/1235 ID가 '1235'인 유저 
 /v1/users/5034/books ID가 '5034인 유저의 대출 도서 

 

리소스 메소드 결정

HTTP 메소드(Verbs)는 단일 인터페이스(Uniform interface) 제약 조건을 구성하는 중요한 요소이며, 동사(Verbs) 기반의 액션과 명사(Noun)기반의 리소스 간 연관관계를 정의한다.
 
 HTTP 메소드  URI 설명 
 GET  /library/books 도서관 장서 전체 
 GET  /library/books/isbn/12345678 ISBN이 '12345678'인 도서 
 POST  /library/books 새로 도서 주문을 한다
 DELETE  /library/books/isbn/12345678 ISBN '12345678'인 도서 정보를 삭제한다
 PUT  /library/books/isbn/12345678 ISBN '12345678'인 도서 정보를 수정한다
 PATCH  /v1/users/1235 ISBN '12345678'인 도서 정보의 일부를  수정한다

HTTP 메서드와 REST

HTTP 메소드는 서버가 URL의 일부로 던져진 데이터를 갖고 어떤 일을 해야할지 알려준다.

GET

  • GET은 가장 간단한 HTTP 메소드로, 리소스에 접근할 수 있게 해준다. 
  • GET은 안전하고 멱등한 메소드다. 
  • GET 요청은 캐시에 보관되며, 요청 문자열 끝에 쿼리 파라미터를 덧붙일 수 있다.
  • 예 : curl http://api.foo.com/v1/users/12345?active=true

POST

  • POST는 리소스를 생성하는 메소드로, POST 요청은 안전하지도 멱등하지도 않다.
  • POST 요청을 여러 번 하면 여러 개의 리소스가 각각 만들어질 수 있고, 캐시 엔트리가 있다면 이를 전부 무효화 시킨다.
  • POST 요청에는 쿼리 파라미터를 붙이지 않는 것이 좋다.
  • 예 : curl -X POST -d'{"name":"Jone Doe","username":"jdoe","phone":"123-4567-8901"}' http://api.foo.com/v1/users
 

PUT

  • PUT은 리소스를 변경하기 위해 사용되며, 멱등하지만 안전하지 않은 메소드이다.
  • PUT 메소드는 여러 차례 호출해도 동일한 리소스를 변경하므로 결과는 동일한다.
  • PUT 요청 역시 캐시 엔트리가 존재할 경우 이를 뭏화시킨다.
  • 예 : curl -X PUT -d'{"phone":"413-344-5677"}' http://api.foo.com/v1/users

DELETE

  • DELETE는 리소스를 삭제하는 메소드이며, 멱등하지만 안전하진 않다. RFC-2616 문서에 따르면 복수의 DELETE 요청은 단일 DELETE 요청과 결과가 동일하므로 멱등하다. 
  • 리소스가 한번 삭제된 후에는 또 다시 DELETE 요청을 여러번 한다 해도 결과는 같기 때문이다.
  • 예 : curl -X DELETE http://api.foo.com/v1/users/1234

HEAD

  • HEAD는 GET과 유사한데, 차이점이 있다면 콘텐츠가 아닌, HTTP 헤더만 리턴한다는 것이다 
  • HEAD는 멱등하고 안전한 메소드이다.
  • HEAD 요청은 GET 요청으로 대용량 데이터를 조회하기 전에 해당 리소스가 변경되었는지 여부만 확인하고 싶을 때 유용하다.
  • curl -X HEAD http://api.foo.com/v1/users

PUT과 POST 차이

  • RFC에는 PUT과 POST의 차이점이 Request-URI에 있다고 설명되어 있다. 
  • POST 메소드는 요청을 처리할 엔티티(Entity)를 Request-URI로 지정하지만, PUT 메소드는 Request-URI 자체에 이미 엔티티가 포함되어 있다.
  • 이를테면, POST /v1/coffees/orders는 주문 데이터를 생성한 뒤 생성된 리소스를 가리키는 식별자를 리턴한다. 반면 PUT /v1/coffees/orders/1234는 주문번호 1234의 리소스가 존재하면 업데이트하고, 존재하지 않을 경우 주문번호가 1234인 데이터를 생성한 뒤 orders.1234를 식별자로 사용한다.
  • PUT, POST 둘다 데이터를 생성하고 업데이트하는 메소드이지만, 메소드의 멱등성과 구별해야 할 리소스의 경로에 따라 사용법이 다르다.

 

리소스 설계에 관한 베스트 프랙티스

API 개발자는 명사와 HTTP 메서드를 사용하여 리소스를 구별하고 이해하기 쉬운 형태로 설계한다.

    • /user/1234/getBook (not OK)
    • /user/1234/books (OK)

서브 리소스(Sub-resource)는 URI를 연관 지어 구별되도록 한다

    • (예) ID가 1234인 유저에 대한 5678번 책의 저자 정보
    • /user/1234/books/5678/authors

그 밖의 조건은 쿼리 파라미터로 지정한다.

    • (예) 10개 이상의 리뷰가 달린 도서 목록을 조회하는 URI
    • /user/1234/books?reviews_counts=10

클라이언트가 원하는 출력 포맷을 지정하지 않을 수도 있기 때문에 기본 포맷을 정한다.

속성은 카멜 또는 언더바 표기법으로 명명한다.

 

URI 설계 시 주의할 점

  • 슬래시 구분자(/)는 계층 관계를 나타내는데 사용
  • URI 마지막 문자로 슬래시(/)를 포함하지 않는다.
  • 하이픈(-)은 URI 가독성을 높이는데 사용
  • 밑줄(_)은 URI에 사용하지 않는다.
  • URI 경로에는 소문자가 적합하다.
  • 파일확장자는 URI에 포함하지 않는다.
 

 

RESTful API 리소스 설계

 

  • REST 리소스 패턴
  • 콘텐츠 협상
  • 엔티티 제공자와 여러 가지 표현형
  • API 버저닝
  • 응답 코드와 REST 패턴
  • 요청/응답 엔티티 직렬화(Serialization), 역직렬화(Deserialization) 하기 위한 커스텀 엔티티 제공자

 

URI에 버전 지정

리소스 URI에 버전을 명시한다.
  • http://api.foo.com/v2/coffees/1234
API 개발자는 기본적으로 최신 버전의 API를 제공해야 한다. 다시 말해 v2가 최신 버전이라면 다음 두 URI는 동일한 리소스를 가리켜야 한다.
  • http://api.foo.com/coffees/1234
  • http://api.foo.com/v2/coffees/1234
클라이언트가 구버전 API에 접속하면 HTTP 에러 코드를 리턴하여 최신 버전 API로 옮겨갈 수 있도록 조치해야 한다.
  • 301 Moved Permanently: 요청한 경로의 리소스가 다른 URI로 영구 이동되었음을 의미한다. 구버전 또는 현재 지원하지 않는 버전의 API를 클라이언트가 사용하려고 할 때 다른 리소스 퍼머링크(Permalink)로 대체되었음을 알린다.
  • 302 Found: 요청한 URI는 아직 유효하지만, 해당 리소스가 임시로 다른 경로에 옴겨졌음을 뜻한다.
 
 
 
 

응답 코드와 REST 패턴

요청에 대한 응답 코드는 HTTP 표준으로 이미 정해져 있다. 다음 표는 CRUD API를 기반으로 한 REST 응답 패턴을 요약하는 것이다.
 
그룹  응답 코드  설명 
 성공 2XX 200 OK  PUT, POST, DELETE 메소드로 각각 생성, 갱신, 삭제 작업을 성공적으로 마쳤다. 요청 데이터가 응답에 포함되어 리턴된다. 
   201 Created PUT 메소드로 리소스가 생성되었다. 응답에 리소스의 Location 헤더가 포함되어 있어야 한다. 
   202 Accepted 서버에서 처리가 아직 안료되지 않아 응답을 보류한 상태로 비동기 요청시 쓰인다. 클라이언트측에서 요청을 모니터링 할 수 있도록 리소스의 Location 헤더를 리턴해야 한다.
   204 Not Content DELETE, POST, PUT 메소드를 사용하여 요청을 처리했지만, 클라이언트에게 응답으로 보내줄 정보가 없을 때 사용한다.  
 리다이렉션 3XX  301 Permanent 모든 요청이 새로운 경로로 리다이렉트 되었다. 
   302 Found 리소스가 이미 존재하고 유효하다. 
 클라이언트 에러 4XX  401 Unauthorized 크리덴셜(Credential)에 문제가 있어 요청을 처리할 수 없다. 
   404 Not Found 리소스를 찾을 수 없다. 인증되지 않은 요청에 의해 정보 유출을 막기 위해서도 이 응답을 보내는 것이 좋다. 
   406 Not Acceptable  클라이언트가 지정한 MIME 타입으로 리소스가 응답할 수 없다. Accept 헤더에 지정된 MIME 타입이 리소스 메소드/클래스의 @Produces 어노테이션으로 지정된 미디어 타입에서 찾을 수 없다.
   415 Unsupported Media Type 클라이언트가 전송한미디어 타입을 리소스가 사용할 수 없다. Content-Type 헤더에 지정된 MIME 타입이 리소스 메소드/클래스의 @Consumes 어노테이션으로 지정된 미디어 타입에서 찾을 수 없다. 
서버 에러 5XX 500 Internal Server error  정확히 원인은 알 수 없지만 서버 측에서 에러가 발생했을 때 보내는 일반적인 응답 코드다. 
   503 Server Unavailable 서버가 점검 중이거나 처리 부하가 극심하여 현재 요청을 처리할 수 없는 상태다. 

 

 

 

 

 

 

 

 

HTTP Verb CRUD Entire Collection (e.g. /customers) Specific Item (e.g. /customers/{id})
POST Create 201 (Created), 'Location' header with link to /customers/{id} containing new ID. 404 (Not Found), 409 (Conflict) if resource already exists..
GET Read 200 (OK), list of customers. Use pagination, sorting and filtering to navigate big lists. 200 (OK), single customer. 404 (Not Found), if ID not found or invalid.
PUT Update/Replace 405 (Method Not Allowed), unless you want to update/replace every resource in the entire collection. 200 (OK) or 204 (No Content). 404 (Not Found), if ID not found or invalid.
PATCH Update/Modify 405 (Method Not Allowed), unless you want to modify the collection itself. 200 (OK) or 204 (No Content). 404 (Not Found), if ID not found or invalid.
DELETE Delete 405 (Method Not Allowed), unless you want to delete the whole collection—not often desirable. 200 (OK). 404 (Not Found), if ID not found or invalid.

(참고) 

 


 

응답 페이지네이션

REST API의 클라이언트에게 대량 데이터를 전송할 경우 적당히 페이지별로 끊어서 전송할 필요가 있다. 이를 응답 페이지네이션이라고 하며, 전체 데이터 건수, 페이지 개수, 다음 페이지로의 링크 등의 메타 정보를 추가로 리턴한다.
 

페이지네이션 유형

  • 오프셋(Offset-based) 페이지네이션
    • 페이지 번호와 페이지당 건수를 정확히 지저앟여 조회할 때 사용한다.
    • GET /v1/coffes/orders?page=1&size=50
쿼리 파라미터   설명
 page 조회할 페이지 번호 
 size 페이지당 조회 가능한 최대 건수 
  • 기간(Time-based) 페이지네이션
      • 특정한 기간에만해당하는 결과를 조회하고자 할 때 사용한다.
      • GET /v1/coffes/orders?since=140358321&until=143087472&size=50
      •  쿼리 파라미터   설명
         until  종료 시점(유닉스 타임스탬프로 표시)
         since  시작 시점(유닉스 타임스탬프로 표시)
         size  페이지당 조회 가능한 최대 건수 
  • 커서(Cursor-based) 페이지네이션
      • 결과 덩어리를 커서의 의해 페이지 단위로 쪼개어 리턴한 후, 응답 객체에 포함된 다음(forward) 커서, 이전(backward) 커서를 사용하여 결과 데이터를 전후로 탐색할 때 사용하는 방법이다.
      • 각 페이지네이션 호출 도중에 리소스가 추가되더라도 중복된 데이터가 리턴되는 것을 방지 할 수 있다. 몇 번을 호출하더라도 파라미터로 지정된 커서가 어디서부터 결과를 찾으면 될지 정확한 위치를 가리키는 포인터이기 때문이다.

 

REST와 마이크로 서비스

SOA가 지향하는 바는 모노리틱한 애플리케이션을 여러 개의 소단위 서비스로 나누어 마이크로 서비스 아키텍처를 구현하는 것이다. 마이크로 서비스가 기존 모노리틱 서비스에 비해 나은 점을 살펴보자.
  • 단순성
  • 문제들을 분리
  • 확장과 축소
  • 기능을 명확하게 분리
  • 프로그래밍 언어 독립
 
 
 

 

'IT > java' 카테고리의 다른 글

Lombok annotation 정리  (0) 2021.10.21
Spring boot + Swagger 3.0  (0) 2021.04.13
eclipse에서 svn offline 설치하기  (0) 2020.04.28
Spring Boot study  메모  (0) 2019.02.27

댓글