RESTful 자바 패턴과 실전 응용: 1장 REST: 태생의 기원

1장 REST: 태생의 기원

SOA 방식의 웹 서비스가 오래동안 활용되어왔음

  • SOAP: Simple Object Access Protocol
  • WSDL: Web Services Description Language
SOAP/WSDL은 XML 기반의 표준이고, 서비스 간 엄격한 규칙이 정립된 상황에서 잘 작동한다. 점점 분산 서비스가 등장하고, 한 서비스는 자신이 클라이언트가 되어 다른 플랫폼에서 제공하는 API를 사용하게 되었다. 따라서, 여러 분산된 서비스 상호간에 손쉽게 정보를 주고 받아야할 필요성이 대두되었다. REST는 HTTP에 기반하여 HTTP가 가능한 곳이면 어디든 쓸 수 있다.

REST 개요

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

REST와 Stateless

REST는 서버의 Stateless를 기본으로 한다. 클라이언트에서 서버로 전달되는 요청에 가능한 모든 정보가 포함되어 있어야 한다. 덕분에 요청에 대한 가시성(visibility), 신뢰성(reliability), 확장성(scalability)이 향상된다.
  • Visibility: 요청에 대한 상세한 정보를 알고 싶을 때, 요청 객체를 다시 파헤쳐보지 않아도 되므로 Visibility가 좋아진다.
  • Reliability: 서버 실행 중 부분적인 장애가 발생하여도 체크 포인트나 실행을 재개할 지점을 고려하지 않아도 되니 신뢰성(reliability)이 향상된다.
  • Scalability: 서버 측에 상태를 따로 보관하지 않기 때문에 서버를 증설한 만큼 비례하여 요청 처리 한도가 증가한다.

리차드슨 성숙도 모델

RMM(Richardson maturity Model)는 레너드 리차드슨이 고안한 모델로 REST를 리소스, 메소드, 하이퍼미디어 등의 용어를 사용해 알기 쉽게 설명한 모델로서 HTTP를 전송 계층의 관점에서 바라보는 것으로 시작한다.
  1. 레벨 0: 원격 프로시저 호출
    • 일반 XML(POX, Plain Old XML) 데이터를 SOAP이나 XML-RPC 등으로 전송한다. POST 메소드만 사용하며, 서비스 간에 단일 POST 메소드로 XML 데이터를 교환한다. 초창기 SOA 애플리케이션 제작 시 흔히 사용된 방식이다.
  2. 레벨 1: REST 리소스
    • 함수에 파라미터 대신 REST URI를 이용.
    • 메소드는 POST만 이용
  3. 레벨 2: 추가 HTTP 메소드
    • POST 외에 GET, HEAD, DELETE, PUT 메소드를 추가적으로 사용
  4. 레벨 3: HATEOAS(Hypermedia as the Engine of Application State)
    • 요청에 대한 하이퍼미디어 응답 속에 클라이언트가 다음에 취해야 할 액션에 관한 상태 정보가 담겨 있다.
    • 리소스 뿐만 아니라 그 이상의 부가적인 정보까지 나타낸다는 점에서 진정한 REST냐는 논란의 여지가 있다.
    • 페이팔 등의 플랫폼에서 HATEOAS를 API의 일부로 구현한 사례가 있음. (5장)

Safe and idempotent

Safe method: 서버의 상태 정보를 변경하지 않는 메소드
GET, HEAD와 같은 안전한 메소드는 캐시가 가능하다. PUT/POST/DELETE 메소드는 서버 리소스를 생성/변경/삭제하므로 안전하지 않다. 

Idempotent method(멱등 메소드): 여러 번을 호출하더라도 동일한 결과를 리턴하는 메소드
GET은 여러 번 호출해도 동일한 응답을 하므로, 멱등.
PUT은 동일한 리소스를 업데이트하고 결과가 달라지지 않으므로 멱등.
POST는 각기 다른 결과가 리턴되거나 새로운 리소스가 계속 만들어질 수 있으므로 멱등하지 않음.
DELETE는 최초 호출 시 리소스가 삭제되고, 이후에 호출해도 결과가 달라지지 않기에 멱등.

RESTful 서비스의 설계 원칙

리소스 URI 결정

명사를 이용하여 URI를 결정. 모든 RESTful 리소스는 URI로 식별된다. 예)
  • /v1/library/books
  • /v1/library/books/isbn/12345678
  • /v1/coffees
  • /v1/coffees/orders
  • /v1/coffees/orders/123
  • /v1/users/1235
  • /v1/users/5034/books

리소스 메소드 결정

GET: 조회. 안전하고 멱등한 메소드
POST: 리소스 생성. 안전하지도 멱등하지도 않은 메소드
PUT: 리소스 변경. 안전하지 않고 멱등한 메소드
DELETE: 리소스 삭제. 안전하지 않고 멱등한 메소드
HEAD: GET과 유사하나 헤더만 리턴 (리소스가 변경되었는지 체크할 때)

PUT과 POST의 차이
PUT, POST 둘 다 데이터를 생성하고, 업데이트하는 메소드이지만, 메소드의 멱등성과 구별해야 할 리소스의 경로에 따라 사용법이 다르다. RFC 2616에 의하면  PUT과 POST의 차이첨이 Request-URI에 있다고 한다. POST는 요청을 처리할 entity를 Request URI로 지정하지만, PUT은 Request-URI에 이미 entity가 포함되어 있다.
예를 들어, POST /v1/coffees/orders는 주문 데이터를 생성한 뒤 생성된 리소스를 가리키는 URI를 리턴한다. 반면, PUT /v1/coffees/orders/1234는 주문번호 1234의 리소스가 존재하면 업데이트하고, 존재하지 않을 경우 주문번호가 1234인 데이터를 생성한뒤 orders/1234를 식별자로 사용한다. 다른 말로, 새로운 리소스의 URI를 클라이언트측에서 결정하는 것이 PUT, 서버측에서 결정하는 것이 POST이다.

리소스 표현형 결정

XML, JSON, HTML, 일반텍스트이 많이 쓰이며, 클라이언트가 어떤 언어와 미디어 타입을 원하는지 먼저 서버에게 알려줄 수도 있다. (2장 콘텐츠 협상 참조)

JAX-RS API 기반 RESTful 서비스 구현

JAX-RS(Java API for RESTful Web Services) REST 스타일로 애플리케이션을 제작, 개발하는데 필요한 API를 정리한 것. JAX-WS는 "Java API for XML Web Services"이다.

@ValidateOnExecution: 실행 시 파라미터나 리턴값에 대한 검증이 필요할 경우 해당 기능을 수행하는 메소드를 지정한다. 3장에서 보다 자세히 설명한다.

RESTful 서비스 배포

WAR 파일 배포 방식임.

RESTful 서비스 테스팅

Client를 활용한 TestClient.java

curl을 이용한 테스트
유용한 옵션

  • -X POST -> 메소드 지정. GET/HEAD/POST/PUT/DELETE
  • -H "foo:bar" -> 요청 헤더에 추가
  • -i -> 응답 헤더를 조회
  • -d '{"name":"John Doe", "username":"jdoe", "phone:123-4567"}' -> 요청 데이터
기타 유용한 툴
  • POSTMAN: JSON/XML 렌더링 및 요청/replay. Install 버전, 크롬 확장 프로그램
  • Advanced REST Client: Google WebToolkit기반의 크롬 확장 프로그램
  • JSONLint: JSON 유효성 체크

몇가지 rule of thumb

  1. 명사형을 이용하라: /users/1234/getBook 보다 /users/1234/books 가 더 좋음
  2. 서브리소스는 URI를 연관지어 구별한다. 예: /users/1234/books/5678/authors
  3. 그 밖의 조건은 쿼리 파라미터로 지정한다. 예: 10개 이상의 리뷰가 달린 도서 목록 조회
  4. 응답 레코드의 일부만 필요할 경우 쿼리 파라미터에 명시한다. 예: /users/1234?fields=name,age
  5. 클라이언트가 원하는 출력 포맷을 지정하지 않을 수도 있기 때문에 기본 포맷을 정한다. 대부분 JSON을 선택한다.
  6. 속성은 카멜 또는 언더바 표기법을 사용한다.
  7. /users/1234/books/count 처럼 개수를 세는 표준 API를 지원하는 것이 좋다.
  8. 깔끔하게 출력할 수 있는 옵션을 제공한다. 예: /users/1234?pretty_print
  9. 서버 응답에는 가능한 한 상세한 내용을 담아서 클라이언트와 서버가 다시 통신할 필요가 없도록 한다.

Reference


댓글

이 블로그의 인기 게시물

[Math] GCD & LCM

Android essentials summary

i++ vs ++i in C and C++