API는 공개 수준에 따라 아래의 3가지로 구분하며, 가능한 높은 공개 수준을 지원해야 한다.
Public API
api.ridibooks.com
api.ridibooks.com/search/api.ridibooks.com/books/Protected API
{team}-api.ridibooks.comapi.{team}.ridi.ioPrivate 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/certsMSA 기반의 서비스들은 개발에 필요한 테스트 환경이 원활하게 제공할 수 있어야 하며 아래 규칙을 준수해야 한다.
.ridi.io로 설정해야 한다.테스트 환경은 무중단으로 운영되지 않을 수 있으므로 사전에 이용을 협의하는 것을 원칙으로 한다.
/reading-notes/{b_id}Query Parameters에는 snake_case 를 사용할 것
/v1, /v2 따위를 포함하지 말 것
Content-Type 헤더를 통한 Media Type 버저닝을 할 것
Accept: application/vnd.ridibooks.cart+json;version=2application/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필드에 명시한다. |