목요일, 6월 09, 2016

RESTful API Service 구현 가이드

RESTful API Service Best Practices
2015년 12월 4일 금요일
오후 1:41

Overview
REST = "REpresentational State Transfer" 네트워크 소프트웨어 아키텍처의 한가지로, 리소스를 정의하고 리소스에 대한 상태를 전송을 표헌하는 전반적인 방법론으로, HTTP 상에서 별로의 전송 계층 없이 리소스를 다루기위한 간단한 인터페이스를 가진다.
예를 들어, 상에서 특정 사용의 주문목록을 조회한다고 했을 , RESTful 다음과 같이 표현될 있다.

[non-RESTful]
/service?userid=1234&action=orderlist
[RESTful]
/users/1234/Oders

위와 같이 URI 만으로 충분히 자체를 서술하고 있으며, 기능적 의미가 표현되므로, API 작정시 또는 서비스 구현시 직관성이 뛰어나며, 리소스에 대한 일관된 주소(표현) 유지보수와 생산성을 동시에 높여준다.

Basic
  1. REST 아키텍처에 적용되는 6가지 제약조건
REST 창시자인 로이 필드의 논문에 제시된 바에 따르면 다음 6가지 제약조건이 REST 적용된다.
단일 인터페이스(Uniform Interface)
무상태(Stateless)
캐시처리가능(Cacheable)
Client-Server
계층화된 시스템
온디멘드 코드(Code on Demand)

단일 인터페이스(Uniform interface)
Client Server 사이의 인터페이스 정의로, 아키텍처를 상호 비종속적이고 독립적으로 구현한다.

리소스 기반(Resource-Based)
  1. URI 통하여 리소스를 식별하고 요청한다.
  2. 리소스 자체는 클라이언트에 반환되는 결과 문서와는 개념적으로 분리된다.
    1. 서버는 데이터베이스 내부의 자료를 직접 전송하는 대신, 데이터베이스 레코드를 HTML, XML이나 JSON 등의 형식으로 표현한다.

표현을 통한 리소스 조작(Manipulation of Resources through representations)
  1. 클라이언트가 리소스을 지칭하는 표현을 알고 있다면 것으로 서버상의 리소스를 수정하거나, 삭제할 있는 충분한 정보를 가진


자기서술적 메시지(Self-descriptive Message()
  1. 각각의 메시지는 자체로 해당 메시지를 어떻게 처리해야 지에 대한 충분한 정보를 알려주어야 한다.
  2. 어떤 미디어 파일 타입에 어떤 파서를 사용해야 할지 알려주어야 한다.

어플리케이션의 상태를 표현하는 하이퍼미디어(Hypermedia)
  1. 클라이언트는 Body 또는, query-string 파라미터, 요청 헤드 요청 URI 통해 상태를 전송한다.
  2. 서비스는 클라이언트에게 상태를 전송할 , 요청의 Body, response code, response 헤드를 통해 상태를 전송한다.
  3. 위와 같은 것이 기술적으로 하이퍼미디어(Hypermedia) 한다.
    1. 또는 하이퍼텍스트에서의 하이퍼링크를 예로 들을 있다.

또한 하이퍼미디어는 필요에 따라, 해당 객체 또는 관련 객체를 참조할 URI 링크를 리턴 Body 포함 때도 사용된다.

상태(Stateless)
  1. RESTful에서 상태(Statelessness) 핵심 키로서
  2. 상태란 말은 요청을 처리하는데 필요한 상태는 요청 자체에 포함되어 있다는 의미
    1. 서버로 요청할 모든 정보는 클라이언트가 가진다.
    2. 상태 값은 URI 부분인, 쿼리-스트링, Body, 혹은 Header 통해 전달
    3. URI 리소스에 대한 식별자
    4. Body에서 리소스의 상태를 포함한다.
    5. 서버에서 요청에 대한 적절한 처리를 다음, 상태 값은 다시 클라이언트에 response Header status 코드를 통해 전달한다.
    6. 서버 컨테이너에서 제공하는 Session 비교
      1. REST에서는 서버는 client 대한 어떠한 상태 정보도 가지고 있지 않는다.
    7. 확장성
      1. 서버는 사용자 세센을 유지하지 않는다.
      2. 부하분산 용이

캐시처리가능(Cacheable)
  1. 클라이언트의 response 캐시
  2. Response 반드시 명시적으로나, 암시적으로 캐시가능 여부를 정의해야 한다.


Client-Server
  1. 관점분리(separation of concerns)
  2. 단일 인터페이스는 서버과 클라이언트의 분리
  3. 클라이언트는 서버의 데이터 저장소, 내부 구조로 부터 독립적이므로, 이식성이 뛰어나다.
  4. 반면 서버는 사용자 인터페이스, 사용자 상태로 부터 분리되어 있으므로, 확장성이 뛰어나다.


계층화된 시스템
  1. 3 구조
  2. Client back-end 서버와 직접적으로 통신하지 않고, 중간 계층이 요청을 중계
  3. 확정성과 부하분산 용이하고, 보안성 강화

온디멘드 코드(Code on Demand)(선택적)
  1. 자바 애플릿이나 자바스크립트의 제공을 통해 서버가 클라이언트가 실행시킬 수 있는 로직을 전송하여 기능을 확장시킬 수 있다



REST API 정의
  1. 동작을 나타내는 HTTP Verbs
    1. GET, POST, PUT, DELETE 통해 CURD 행위를 처리

분별력 있는 리소스 명명
  1. /asp?type=posts&id=23 같은 경로보다는 /posts/23 같이 보다 요청이 하고자 하는 바를 보다 명확하게 한다.
  2. 적절한 리소스명은 이름 자체만으로 풍부한 설명이 되므로, 이해력이 된다. 따라서 서술적이고 사용자 친화적인 명칭을 사용하도록 한다

XML JSON
  1. 기본적으로 JSON 지원하고, 경우에 따라서는 JSON XML 모두 지원하도록 한다.
  2. 확장자 변경함으로써 .xml 에서 .json 으로 쉽게 변경할 있게 지원


정의(Definitions)
  1. 멱등성(Idempotence)
    1. In computer science, the term idempotent is used more comprehensively to describe an operation that will produce the same results if executed once or multiple times.  This may have a different meaning depending on the context in which it is applied. In the case of methods or subroutine calls with side effects, for instance, it means that the modified state remains the same after the first call.
, 코드의 재진입성과 유사한 개념으로, RESTful이란 요청을 여러 호출하더라도, 동일한 결과를 가져다 주어야 한다.

안전성(Safety)
  1. GET 요청은 안전적이다. 메소스는 정보를 조회는 하나, 결코 서버의 상태를 수정할 없다.
  2. 따라서, GET 같은 요청은 읽기전용으로 안전하게 처리되어야 한다.

HTTP 메소드
  1. GET
    1. HTTP 정의상 GET 메소드는 리소스로 부터 정보를 읽는다(수정불가)
    2. GET 메소드는 정상적으로 처리될 경우, 응답코드 200 함께 XML 이나, JSON 리턴
    3. )
      1. GET http://www.example.com/customers/12345
      2. GET http://www.example.com/customers/12345/orders
      3. GET http://www.example.com/buckets/sample

GET 메소드는 Idempotence

PUT
  1. 리소스를 수정할 사용
  2. 경우에 따라, 리소스 ID 서버가 아닌 클라이언트에 의해 지정된 경우 PUS 메소드로 리소스를 생성할 있다.
    1. , PUT 메소드가 존재하지 않는 리소스 ID 가지고 있는 경우라 있음

)
  1. PUT http://www.example.com/customers/12345
  2. PUT http://www.example.com/customers/12345/orders/98765
  3. PUT http://www.example.com/buckets/secret_stuff
성공시 200 리턴
만약 리소스 생성인 경우 201 리턴
  1. 리소스 생성시 Location 헤더에 생성한 리소스 ID 반환한다.
    1. Location=http://www.example.com/customers/12345

PUT 메소스는 비안전 메소드

POST
  1. POST 메소드는 새로운 리소스를 생성할 사용
  2. )
    1. POST http://www.example.com/customers
    2. POST http://www.example.com/customers/12345/order
  3. 성공시 201 리턴하고, Location 헤더에 생성한 리소스 ID 반환한다.
  4. POST 메소드는 SAFE 하지도 않고 Idempotent 하지도 않는다.

PUT/POST 리소스 생성
  1. 일반적으로 POST 사용
  2. 그러나, 이미 클라이언트가 생성할 리소스 ID 알고 있거나, 책임이 있는 경우 PUT 사용한다.

DELETE
  1. 리소스 삭제에 사용
  2. )
    1. DELETE http://www.example.com/customers/12345
    2. DELETE http://www.example.com/customers/12345/orders
    3. DELETE http://www.example.com/buckets/sample

삭제 성공시 200리턴
실패시 204(NO CONTENT) 반환
Idempotent 메소드(삭제한 리소스에 대해 다시 삭제 하도라도 동일)이나,
존재하지 않는 리소스를 삭제시에는 404(NOT FOUND) 반환

HTTP 메소드 리턴값




리소스 명명(Resource Naming)
  1. URI , 리소스 명명은 좋은 API 만드는데 있어, 매우 중요
  2. RESTful이란 결국 단순히 URI 집합을 말하여, 이런 URI HTTP 통해 호출하고, JSON 이나, xml 형태로 리소스를 표현한 것이라 있다.

명사를 사용하여 리소스명을 표현하고, 동사는 행위(action) 표현한다.
)
  1. Users of the system.
  2. Courses in which a student is enrolled.
  3. A user's timeline of posts.
  4. The users that follow another user.
  5. An article about horseback riding.

사용자 관점에서 명명
Resource URI Examples
To insert (create) a new customer in the system, we might use:
POST http://www.example.com/customers

To read a customer with Customer ID# 33245:
GET http://www.example.com/customers/33245
The same URI would be used for PUT and DELETE, to update and delete, respectively.

Here are proposed URIs for products:
POST http://www.example.com/products
for creating a new product

GET|PUT|DELETE http://www.example.com/products/66432
for reading, updating, deleting product 66432, respectively.

다음 URI 의미하는 바는 무엇일까?
POST http://www.example.com/customers/33245/orders

GET http://www.example.com/customers/33245/orders

POST http://www.example.com/customers/33245/orders/8769/lineitems

GET http://www.example.com/customers/33245/orders/8769/lineitems/1

리소스 명명 안티패턴(Resource Naming Anti-Patterns)
  1. 적합하지 않는 RESTful 리소스 URI
  2. 하나의 URI 서비스 인터페이스를 만들어, query-string으로 요청의 동작을 처리하는 경우
GET http://api.example.com/services?op=update_customer&id=12345&format=json --> poor

사용자 업데이트 URI
GET http://api.example.com/update_customer/12345
GET http://api.example.com/customers/12345/update

복수명칭(Pluralization)
  1. 리소스 명에 복수를 취할 것인가, 아니면 단수를 취할 것인가?
    1. GET http://www.example.com/customer/33245
    2. GET http://www.example.com/customers/33245

리소스는 보통 집합을 나타내므로, 복수를 사용
  1. GET http://www.example.com/customers/33245/orders/8769/lineitems/1
  2. POST http://www.example.com/customers
  3. GET|PUT|DELETE http://www.example.com/customers/{id}

경우에 따라서, 복수 개념이 없이 하나의 리소스임이 명확한 경우 단수를 사용
  1. GET|PUT|DELETE http://www.example.com/configuration
    1. 사용자 마다, 환경 구성 값은
  2. GET|PUT|DELETE http://www.example.com/customers/12345/configuration

리턴 문서포맷(Returing Representations)
  1. 리턴 문서는 JSON, XML
    1. GET http://www.example.com/customers.xml
      1. Xml 포맷으로 반환
    2. GET http://www.example.com/customers/12345
      1. 기본값이 생략된 경우 json 포맷사용
    3. GET http://www.example.com/customers/12345.json
      1. Json 포맷임을 명시
    4. 반환 문서 포맷이 지원되지 않을 경우 404 오류 리턴


링크 포맷(Link Format) 권장
  1. POST http://api.example.com/users

HTTP/1.1 201 CREATED
Status: 201 Connection: close
Content-Type: application/json; charset=utf-8
Location: http://api.example.com/users/12346

GET 요청
{“data”:[{“user_id”:”42”, “name”:”Bob”, “links”:[{“rel”:”self”, “href”:”http://api.example.com/users/42”}]}, {“user_id”:”22”, “name”:”Frank”, “links”: [{“rel”:”self”, “href”:”http://api.example.com/users/22”}]}, {“user_id”:”125”, “name”: “Sally”, “links”:[{“rel”:”self”, “href”:”http://api.example.com/users/125”}]}]}

{"code":200,"status":"success","data": {"lacksTOS":false,"invalidCredentials":false,"authToken":"4ee683baa2a3332c3c86026d"}}
{"code":401,"status":"error","message":"token is invalid","data":"UnauthorizedException"}

<response> 
<code>200</code> 
<status>success</status> 
<data class="AuthenticationResult">   
<lacksTOS>false</lacksTOS>   
<invalidCredentials>false</invalidCredentials>   
<authToken>1.0|idm|idm|4ee683baa2a3332c3c86026d</authToken>
 </data>
</response>



쿼리, 필터, 페이징처리
  1. 결과값 제한
    1. Limiting via the Range Header
HTTP 헤더에 제한값 설정
Range: items=0-24

Limiting via Query-String Parameters
  1. GET http://api.example.com/resources?offset=0&limit=25

Range-Based Responses
 the server should respond with a Content-Range header to indicate how many items are being returned and how many total items exist yet to be retrieved:
Content-Range: items 0-24/66
Content-Range: items 40-65/66
Content-Range: items 40-65/*

Pagination
Via query-string parameters, this would be equivalent to:

GET ...?offset=25&limit=25
  1. Range: items=25-49
  2. Content-Range: 25-49/66 와 동일

For example, to retrieve up to 20 remarks around a given timestamp:
GET http://www.example.com/remarks/home_timeline?after=<timestamp>
Range: items=0-19

GET http://www.example.com/remarks/home_timeline?before=<timestamp>
Range: items=0-19

Equivalently, using query-string parameters:
GET http://www.example.com/remarks/home_timeline?after=<timestamp>&offset=0&limit=20
GET http://www.example.com/remarks/home_timeline?before=<timestamp>&offset=0&limit=20

Filtering
  1. GET http://www.example.com/users?filter="name::todd|city::denver|title::grand poobah”

Sorting
  1. GET http://www.example.com/users?sort=last_name|first_name|-hire_date

Service Versioning
  1. Support Versioning via Content Negotiation
어플리케이션 수정 또는 요구사항 변경 , 다양한 이유로 인해, 버저닝이 필요







버전이 지정되지 않은 경우 기본 버전



지원되지 않는 버전요청시


이상 지원되지 않는 버전 요청시


Date/Time Handling
  1. Date/Time Serialization In Body Content
    1.  ISO 8601 time point format is a good solution, using the fully-enhanced format that includes hours, minutes, seconds and a decimal fraction of seconds (e.g. yyyy-MM-dd'T'HH:mm:ss.SSS'Z'

https://github.com/tfredrich/DateAdapterJ
 ISO8601 Timepoints are:
  1. http://momentjs.com/
  2. http://www.datejs.com/

보안(Securing Service)

  1. Securing process




인증(Authentication)
  1. OAuth2 권장
    1.  http://oauth.net/documentation/spec/.

전송 보안(Transport Security)
  1. 모든 인증에 반드시 SSL사용
  2. OAuth2 서버 권한처리 access token 인증에 TLS 요구
  3. HTTP HTTPS 사이의 전환은 보안상 취약하므로 항상 TLS 통신 사용

권한처리(Authorization)
Application Security

Caching and Scalability






The ETag Header
The ETag header is useful for validating the freshness of cached representations
The value for the ETag header can be as simple as a hash of the underlying domain object (e.g. Object.hashcode() in Java)

 It is recommended to return an ETag header for each GET (read) operation


ETag: "686897696a7c876b7e"

댓글 없음: