RestApi 디자인 가이드

LikeChoonsik's·2022년 12월 22일
0

Common

목록 보기
3/7
post-thumbnail

REST란?

REST(REpresentational State Transfer)

자원을 이름(자원의 표현)으로 구분하여 해당 자원의 상태를 주고 받는 아키텍쳐

  • REST는 웹의 창시자(HTTP) 중의 한 사람인 Roy Fielding(로이 필딩)이 2000년 논문에서 소개합니다. 현재의 아키텍처가 웹의 본래 설계의 우수성을 많이 사용하지 못하고 있다고 판단했기 때문에, 웹의 장점을 최대한 활용할 수 있는 네트워크 기반의 아키텍처를 소개했는데 그것이 바로 Representational safe transfer (REST)입니다.
  • 웹에 존재하는 모든 자원(이미지, 동영상, DB)에 고유한 URI를 부여해 활용 하는 것입니다.
  • RESTful: REST 원리를 따르는 시스템으로 REST 특징을 지키면서 API를 제공하는 것입니다.

HTTP 프로토콜을 그대로 사용하기에 웹의 장점을 최대한 활용할 수 있음

Clinet와 Server 사이의 통신 방식 중 하나

REST API의 탄생 배경

👉 이전과 달리 최근에는 멀티 플랫폼, 멀티 디바이스 시대로 넘어와 있어서 여러 웹 브라우저와 아이폰, 안드로이드 애플리케이션과의 통신에 대응할 수 있어야 한다.
👉 이런 시대에 맞춰 각각 대응하는 새로운 서버를 만들기보다 범용적으로 사용성을 보장하는 서버 디자인이 필요하게 되어 Rest API가 개발되었다.

구체적 개념

HTTP URI를 통해 자원을 명시하고, HTTP Method 4항목 (POST, GET, PUT, DELETE)를 통해 해당 자원에 CRUD를 적용할 수 있도록 설계한 방식

REST API 구성요소

👉 자원(Resource): HTTP URI

모든 자원에 고유한 ID가 존재하고, 이 자원은 Serverd에 존재한다.
자원을 구별하는 ID는 HTTP URL이다.
Client는 URL를 이용해서 자원을 지정하고, 해당 자원의 상태(정보)에 대한 조작을 Server에 요청한다.
👉 자원에 대한 행위(Verb): Http Method

HTTP 프로토콜의 메소드를 사용한다.
HTTP 프로토콜은 GET, POST, PUT, PATCH, DELETE와 같은 메소드를 제공한다.

Method	역할
POST	새로운 자원을 추가할 때 사용한다.
GET	    자원을 받아오기만 할때 사용한다.
PUT	    존재하는 자원을 변경할때 사용한다.
PATCH	한 자원의 데이터를 부분적으로 변경할 때 사용한다.
DELETE	자원을 삭제할때 사용한다.

👉 표현(Representation of Resource): HTTP Message Pay Load

Client가 자원에 대한 상태(정보)에 대한 조작을 요청하면 Server는 이에 적절한 응답(Represention)을 보낸다.
Rest에서 하나의 자원은 JSON, XML, TEXT, RSS등 여러 형태의 Representaion으로 나타낼 수 있다.
JSON 혹은 XML를 통해 데이터를 주고 받는 것이 일반적이다.

REST의 특징

👉 클라이언트/서버 구조:

클라이언트는 유저와 관련된 처리를, 서버는 REST API를 제공함으로써 각각의 역할이 확실하게 구분되고 일괄적인 인터페이스로 분리되어 작동할 수 있게 한다.
REST Server: API를 제공하고 비지니스 로직 및 저장을 책임진다.
Client: 사용자 인증이나 context(세션, 로그인 정보)등을 직접 관리하고 책임진다.
서로 간의 의존성이 줄어든다.

👉 무상태성(Stateless):

REST는 HTTP의 특성을 이용하기 때문에 무상태성을 갖는다.
즉 서버에서 어떤 작업을 하기 위해 상태정보를 기억할 필요가 없고 들어온 요청에 대해 처리만 해주면 되기 때문에 구현이 쉽고 단순해진다.

👉 캐시 처리 가능(Cacheable):

HTTP라는 기존 웹표준을 사용하는 REST의 특징 덕분에 기본 웹에서 사용하는 인프라를 그대로 사용 가능하다.
대량의 요청을 효율적으로 처리하기 위해 캐시가 요구된다.
캐시 사용을 통해 응답시간이 발라지고 REST Server 트랜잭션이 발생하지 않기 때문에 전체 응답시간, 성능, 서버의 자원 이용률을 향상 시킬 수 있다.

👉 자체 표현 구조(self-descriptiveness):

JSON을 이용한 메시지 포멧을 이용하여 직관적으로 이해할 수 있고 REST API 메시만으로 그 요청이 어떤 행위를 하는지 할 수 있다.

👉 계층화(Layered System):

클라이언트와 서버가 분리되어 있기 때문에 중간에 프록시 서버, 암호화 계층 등 중간매체를 사용할 수 있어 자유도가 높다.

👉 유니폼 인터페이스(Uniform Interface):

Uniform Interface는 HTTP 표준에만 따른다면 모든 플랫폼에서 사용이 가능하며, URI로 지정한 리소스에 대한 조작을 가능하게 하는 아키텍쳐 스타일을 말한다.
URI로 지정한 Resource에 대한 조작을 통일되고 한정적인 인터페이스로 수행한다.
특정 언어나 기술에 종속되지 않는다.

REST의 단점

👉 표준이 존재하지 않는다.
👉 사용할 수 있는 메소드가 CRUD 4가지 밖에 없다.
👉 HTTP에 상당히 의존적이다. REST는 설계 원리이기 때문에 HTTP와는 상관없이 다른 프로토콜에서도 구현할 수 있기는 하지만 자연스러운 개발이 힘들다. 다만 REST를 사용하는 이유가 대부분의 서비스가 웹으로 통합되는 상황이기에 큰 단점이 아니다.
👉 REST는 URI, HTTP를 이용한 아키텍쳐링 방법에 대한 내용만을 담고 있다. 보안과 통신규약 정책 같은 것은 전혀 다루지 않는다. 따라서 개발자는 통신과 정책에 대한 설계와 구현을 도맡아서 진행해야 한다.
👉 구형 브라우저가 지원해주지 못하는 부분이 존재한다. (PUT, DELETE를 사용하지 못함/PushState를 지원하지 않음)

RESTful 하다?

RESTful하다란, REST의 원리를 따르는 시스템을 의미한다. 하지만 REST를 사용했다 하여 모두가 RESTful한 것은 아니며, REST API 설계 규칙을 올바르게 지킨 시스템을 RESTful하다 말할 수 있다.
따라서 모든 CRUD 기능을 POST로 처리 하는 API 혹은 URI 규칙을 올바르게 지키지 않은 API는 REST API의 설계 규칙을 올바르게 지키지 못한 시스템은 REST API를 사용했지만 RESTful하지 못한 시스템이라고 할 수 있다.

용어 정리

  • 리소스(Resource): 데이터의 일부입니다. (예. user)
  • 콜렉션(Collection): 리소스의 집합입니다. (예. users)
  • URL(Identifies the location): 리소스 혹은 콜렉션을 식별할 수 있는 경로입니다.
  • (예./company/google/employee/12)

REST API 디자인 가이드

1. URL에 케밥케이스(kebab-case)를 사용하자

orders의 목록을 반환하는 API를 만든다고 해봅시다.

Bad:

[GET] /systemOrders
[GET] /system_orders

Good:

[GET] /system-orders

2. Path Variable에는 카멜케이스(camelCase)를 사용하자

주문내역 조회 URL을 만든다고 해봅시다. 주문내역이라는 Orders 하위에 orderId가 있을 것입니다. Path Variable에 해당하는 orderId는 카멜케이스를 사용합시다.

Bad:

[GET] /orders/{order_id}
[GET] /orders/{OrderId}

Good:

[GET] /orders/{orderId}

3. Collection에는 단수가 아닌 복수를 사용하자

사용자들 전체를 조회하는 URL에 User의 집합이므로 복수를 사용합니다.

Bad:

[GET] /user
[GET] /User

Good:

[GET] /users

4. Collection으로 시작해서 Identifier로 끝나자

Bad:

GET /shops/{shopId}/category/{categoryId}/price

리소스 대신에 price라는 속성을 가리키기 때문에 좋지 않습니다.

Good:

GET /shops/{shopId}
GET /category/{categoryId}

상점 목록이라는 콜랙션으로 시작해서 하위에 속한 하나의 shopID라는 Identifier로 끝났습니다.

5. 동사보다 명사를 사용하자

Bad:

[POST] /updateuser/{userId}
[GET] /getusers

행위를 URL에 붙인 경우 좋지 못합니다.

Good:

[PUT] /user/{userId}

HTTP Method를 이용해서 CRUD(생성, 읽기, 수정, 삭제)를 수행한다는 것을 알 수 있어야합니다.

6. Non-Resource URL에는 동사를 사용하자

특정 작업을하고 응답으로 아무것도 하지 않는 경우 URL에 동사를 사용할 수 있습니다. 유저에게 알림을 보내는 URL을 다음과 같이 쓸 수 있습니다.

Good:

POST /alerts/245743/resend

7. 가급적 소문자를 쓰자

RFC 3986(URI 문법 형식)은 URI 스키마와 호스트를 제외하고는 대소문자를 구별하도록 규정하고 있습니다. 대소문자를 썪어 쓰는 것은 가능하지만 URI를 기억하기 어려우며 실수할 가능성이 높아집니다. 가급적 URI는 소문자로 작성하는 것을 권장합니다.

Bad:

[GET] /users/1/PROFILE

Good:

[GET] /users/1/profile

8. HTTP 메서드로 표현하자

HTTP 메서드를 통해서 CRUD 중 무엇을 수행하는지 알 수 있어야합니다.

  • GET: 리소스 정보를 조회합니다.
  • POST: 새로운 리소스를 생성합니다.
  • PUT: 존재하는 리소스를 수정합니다.
  • PATCH: 제공된 리소스를 업데이트합니다. 제공된 필드만 업데이트하고 나머지 필드는 그대로둡니다.
  • DELETE: 존재하는 리소스를 삭제합니다.

update라는 동작이 들어가서 안됩니다. PUT 메서드를 이용하여 리소스를 수정한다는 정보를 줄 수 있습니다.

Bad:

[GET] /posts/update/1
[GET] /users?method=update&id=covenant

Good:

[PUT] /posts/1

예시.

  • GET /shops/2/products: shop 2에서 판매하는 모든 상품을 조회합니다.
  • GET /shops/2/products/31: shop 2에서 판매하는 31번 상품을 조회합니다.
  • DELETE /shops/2/products/31: shop 2에서 판매하는 31번 상품을 삭제합니다.
  • PUT /shops/2/products/31: shop 2에서 판매하는 31번 상품의 정보를 수정합니다.
  • POST /shops : 새로운 shop을 생성합니다.

9. 적절한 상태값을 응답하자

잘 설계된 REST API는 URI만 잘 설게된 것이 아니라 리소스에 대한 응답을 잘 전달해야합니다. 정확한 응답의 상태코드는 많은 정보를 전달할 수 있습니다.

응답 상태 코드는 RFC 2616에 정의되어 있습니다. 상태코드는 크게 다섯개의 그룹으로 나눕니다. (참고 RFC 2616: https://tools.ietf.org/html/rfc2616#section-10)

  • Informational 1XX: 정보를 제공하는 응답
  • Successful 2XX : 성공적인 응답
    • 200 OK: 요청이 성공적으로 수행
  • Redirection 3XX
    • 메시지 클라이언트의 요청을 완료하기 위해서 추가적인 행동이 필요한 경우
  • Client Error 4XX
    • 클라이언트가 서버에게 잘못된 요청을 하는 경우
    • 401 Unauthorized: 인증이 필요한 페이지를 요청한 경우
    • 403 Forbiden: 허용되지 않은 메소드가 있을 때
    • 406 Not Acceptable: 허용 불가능
  • Server Error 5XX
    • 서버에서 오류가 발생하여 정상적으로 요청을 처리할 수 없는 경우
    • 500 Internal Server Error: 웹 서버가 처리할 수 없음
    • 503 Service Unavailable: 서비스 제공불가, 서버 과부하, 서버 폭주

또한 에러 내용에 대한 상세 내용을 http body에 정의해서 상세한 에러 원인을 전달하는 것이 디버깅에 좋습니다.

다음은 Kakao Open API에서 카카오 로그인 응답 예시입니다. 상태메시지를 통하여 400 Status Code를 응답한 이유를 담고있습니다. (참고. developers.kakao)

HTTP/1.1 400 Bad Request
{
    "msg":"user property not found ([gender, age] for appId={APP_ID})",
    "code":-201
}

10. JSON property에는 카멜케이스(camelCase)를 사용하자

Bad:

{
    user_id: "1"
    user_name: "Covenant"
}

Good:

{
     userId: "1"
   userName: "Covenant"
}

11. URI에 파일 확장자를 포함하지 않는다.

URL에 파일확장자를 포함하지 않는 대신에 클라이언트가 허용할 수 있는 파일 형식 정보가 있는 Accept header를 사용합니다.

Bad:

[GET] /users/1/profile.png

Good:

[GET] covenant.tistory.com/users/1/profile-img
Accept: image/jpg

12. API 버전을 위해서 서수를 사용하자

하위호한성을 위하여 API에 버전을 넣어야합니다. 새로운 기능이 들어간 API를 제공할때 이전 API와 구분하기 위해서 서수를 사용하여 URL의 상단의 경로에 넣습니다. (참고: developers.kakao)

Good:

https://kapi.kakao.com/v2/user/me

13. list 리소스의 경우 갯수도 함께 응답하자

리스트 형식의 객체를 응답할때 응답하는 리스트의 갯수를 응답하는것이 좋습니다. 페이지네이션 등 API 이용자가 다양하게 사용할 수 있습니다.

Bad:

{
  users: [
     ...
  ]
}

Good:

{
  users: [
     ...
  ],
  total: 34
}

14. 리스트 응답의 경우 파라미터로 limit과 offset 정보를 받자

다수의 정보를 조회하는 경우 limit, offset의 정보를 파라미터로 받아서 응답하세요. API를 응답받기 전까지 몇개의 리스트가 내려올지 알지 못합니다. 하나의 API 호출로 1만개(640kb)를 응답한 적도 있습니다. 이용자가 많다면 서비스 응답시간이 오래 걸리거나 언제 죽더라도 이상하지 않을 것입니다.

limit, offset 값을 이용하여 프론트에서 페이지네이션을 구현할 수 있습니다.

Good:

GET /shops?offset=5&limit=5

15. 쿼리 파라미터를 위한 매개변수를 가져오자

응답하는 데이터 양을 고려해야합니다. 다음의 예처럼 fields 파라미터를 이용하여 API에서 응답하는 데이터 값을 정할 수 있습니다.

Good:

GET /shops?fields=id,name,address,contact

id, name, address 그리고 contact 정보만 받습니다. 이를 통해서 응답값 크기를 줄일 수 있습니다. 하나의 API로 모바일과 웹 브라우저에서 호출할 때 일반적으로 모바일 환경은 웹 브라우저보다 화면에 보여주는 데이터 양이 적습니다. 웹 브라우저처럼 사용하지 않은 모든 데이터를 내려받는다면 불필요한 데이터를 다운로드하게 할 것입니다.

16. 인증토큰을 URL에 노출하지 말자

최근 JWT를 이용하여 토큰 인증 방식으로 구현이 늘어나고 있습니다. 인증토큰이 URL에 노출되도록 구현하면 안됩니다.

Bad:

GET /shops/123?token=some_kind_of_authenticaiton_token

Good:

Authorization: Bearer xxxxxx, Extra yyyyy

요청 Header에 넣는 것이 좋습니다. 또한 Token은 짧은 유효기간을 부여하여 탈취에 대비해야합니다.

17. URI의 마지막 문자로 슬래시(/)를 포함하지 말자.

url의 마지막에 슬래시(Trailing slash)가 붙어있다면 이는 리소스가 디렉토리라는 의미입니다.

Bad:

[GET] /users/1/profile/

Good:

[GET] /users/1/profile

18. 리소스 이름에는 테이블명을 사용하지마라

리소스 이름을 통해서 아키텍처적인 정보가 노출되는 것은 좋지 못합니다.

Bad:

product_order

Good:

product-orders

19. API 문서화 도구를 사용하자

다음과 같은 API 문서화 도구가 있습니다.

문서화 도구를 통해서 정확한 API정보를 API를 이용하는 사용자, 프론트엔드 개발자들에게 제공할 수 있습니다.

20. 모니터링

RESTfull HTTP서비스를 위해서 /health, /version, /metrics API 엔드포인트를 만들어야합니다.

  • /health: 200OK 상태값을 반환합니다. (해당 API가 정상 연결되었지 체크할 수 있습니다.)
  • /version: API버전 숫자를 응답합니다.
  • /metrics: 평균 응답 시간과 같은 다양한 metrics을 응답합니다.

이외에도 /debug 혹은 /status와 같은 API 엔드포인트를 사용할 수 있습니다.

원문:https://covenant.tistory.com/241

profile
춘식이는 너무 귀엽습니다.

0개의 댓글