API는 공개 수준에 따라 아래의 3가지로 구분하며, 가능한 높은 공개 수준을 지원해야 한다.
Public API
api.ridibooks.com
api.ridibooks.com/search/
api.ridibooks.com/books/
Protected API
{team}-api.ridibooks.com
api.{team}.ridi.io
Private API
마이크로서비스를 운영하다보면 내부 서버간, 즉 신뢰할 수 있는 서버간의 API 통신이 필요한 상황이 발생한다. 이 때 인가는 JWT(JSON Web Tokens)를 통해 이루어져야 하며, 사용되는 토큰은 아래의 조건을 만족해야 한다.
Authorization
헤더의 Bearer
토큰으로 전달예) 구매목록 서비스에서 책 서비스의 API를 호출하는 경우
{ // header
"typ": "JWT",
"alg": "RS256"
}
{ // payload
"iss": "library",
"aud": "book",
"exp": 1531819973
}
마이크로서비스 환경에서 최종사용자의 SSO(Single Sign-On)를 지원하기 위해 OAuth2를 사용한다. 이 때 access token은 JWT(JSON Web Tokens) 형태로 발급되며, 사용되는 토큰은 아래의 조건을 만족해야 한다.
예)
{ // header
"typ": "JWT",
"alg": "ES256"
}
{ // payload
"u_idx": 12312233,
"sub": "antiline",
"exp": 1518505258,
"client_id": "**given_client_id**",
"scope": "all"
}
RSA 혹은 ECDSA 기반으로 JWT를 서명하는 경우 JSON Web Key Set (JWKS) 형식으로 공개키 집합을 전달한다. JWKS는 키 로테이션을 위한 표준화된 수단을 제공하므로, 기존에 사용하고 있던 PEM 형식의 파일 전달 방식을 대체한다.
JWK 객체는 아래의 조건을 만족해야 한다.
"RSA"
혹은 "EC"
"RSA"
인 경우 alg(Algorithm)는 반드시 "RS256"
"EC"
인 경우 crv(Curve)는 반드시 "P-256"
"sig"
예)
{
"keys": [{
"kid":"1234example=",
"kty":"EC",
"crv":"P-256",
"use":"sig",
"x":"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
"y":"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM"
}, {
"kid": "5678example=",
"kty": "RSA",
"alg": "RS256",
"use": "sig",
"e": "AQAB",
"n": "987654321"
}]
}
https://www.googleapis.com/oauth2/v3/certs
MSA 기반의 서비스들은 개발에 필요한 테스트 환경이 원활하게 제공할 수 있어야 하며 아래 규칙을 준수해야 한다.
.ridi.io
로 설정해야 한다.테스트 환경은 무중단으로 운영되지 않을 수 있으므로 사전에 이용을 협의하는 것을 원칙으로 한다.
/reading-notes/{b_id}
Query Parameters에는 snake_case 를 사용할 것
/v1
, /v2
따위를 포함하지 말 것
Content-Type
헤더를 통한 Media Type 버저닝을 할 것
Accept: application/vnd.ridibooks.cart+json;version=2
application/json
을 사용할 것다양한 response code를 사용하면 그 자체로 명시적이지만 코드 관리가 어려워진다는 단점이 있다. 따라서 아래 명시된 보편적인 response code만을 사용하고 더 자세한 내용은 message-body에서 제공한다.
상태 코드 | 의미 | 용도 |
---|---|---|
200 OK | 성공적으로 처리 | 에러 응답에 대해서 사용하지 않도록 한다 |
201 Created | 리소스 생성 완료 | 가능하면 응답 헤더 Location필드에 리소스를 접근할 수 있는 URI를 포함시킨다. |
204 No Content | 내용없음 | 요청 처리 성공 후 특별히 message body에 포함시킬 내용이 없는 경우 사용한다. |
301 Moved Permanently | 요청한 리소스가 새로운 URI를 부여받았음 | 새 URI를 응답 헤더 Location필드에 명시한다. |
302 Found | URI가 임시로 변경됨 | 301과 비슷하지만 일시적으로 옮겨진 경우에만 사용한다. |
304 Not Modified | 요청한 리소스가 변경되지 않음 | If-Modified-Since 요청 헤더에 대한 응답으로 활용될 수 있다. |
400 Bad Request | 잘못된 요청 | 정의되지 않은 형식이나 보내면 안되는 요청에 대한 응답. |
401 Unauthorized | 리소스 접근 권한이 없음 | 가능하면 응답에 인증에 관한 정보를 포함시켜 필요한 경우 클라이언트에서 추가 요청을 보낼 수 있도록 한다. |
403 Forbidden | 숨겨진 리소스에 접근하려 함 | 필요하다면 거부된 이유를 응답에 포함시키고,아예 공개할 의사가 없다면 404: Not Found를 사용한다. |
404 Not Found | 매칭되는 URI가 없음 | 실제 리소스가 존재하더라도 존재 여부를 노출시키지 않고 싶은 경우에 사용할 수 있다. |
429 Too Many Requests | 너무 많은 요청 | 가능하면 얼마나 기다린 후에 새로운 요청을 받을 수 있는지 응답 헤더의 Retry-After필드에 명시한다. |
500 Internal Server Error | 서버 에러 | 요청은 정상적으로 받았지만 서버 처리 중 문제가 발생할 경우 전반에 사용한다. |
502 Bad Gateway | 게이트웨이 에러 | 서버가 게이트웨이나 프록시로 사용 중인 경우 upstream서버에 이상이 있을 때 사용한다. |
503 Service Unavailable | 서비스 이용 불가 | 대기 시간을 알 수 있다면 응답 헤더의 Retry-After필드에 명시한다. |