티스토리 뷰

Server & Etc

RESTful API 작성 팁

nc2u 2019. 9. 26. 23:44

1. 알맞는 HTTP 메서드를 사용한다.

리소스의 상태를 읽을 때는 GET, 상태를 변경할 때는 POST, PUT, DELETE 메서드를 쓴다.

DELETE /articles/1            # (O)
GET /deleteArticles?id=1      # (X)

2. HTTP 메서드 오버라이드

오래된 브라우저 또는 일부 네트워크 프록시는 GET, POST 메서드만 쓸 수 있다. 이처럼 기능 제약이 있는 클라이언트가 PUT이며, DELETE 요청을 할 때는 POST 메서드를 쓰고 _method=put과 같이 힌트를 제공할 수 있도록 해야 한다.

POST /articles

---payload---
_method=PUT&title=...&content=...

라라벨은 X-HTTP-Method-Override HTTP 헤더를 이용한 메서드 오버라이드도 지원한다.

POST /articles
X-HTTP-Method-Override=PUT

---payload---
title=...&content=...

3. 명사형의 컬렉션과 인스턴스 엔드포인트

리소스는 서버에 저장된 데이터, 즉 모델을 의미한다. API를 사용하는 클라이언트에게는 URL로 표현한다. 문맥에 따라 엔드포인트(endpoint)라는 표현을 쓰기도 한다.

REST를 따르면 URL 엔드포인트는 컬렉션과 인스턴스, 두 가지 종류밖에 없다.

 

형태 리소스(엔드포인트) GET POST PUT DELETE
컬렉션 /articles 글 목록 글 저장 없음 없음
인스턴스 /articles/{id} {id}번 글 상세 보기 없음 글 수정 글 삭제

 

API 개발에서는 HTML 뷰를 다루지 않기 때문에 이를 반환하는 라우팅인 GET /articles/create와 GET /articles/{id}/edit는 필요 없다.

어쩔 수 없는 경우가 아니면 동사는 쓰지 말자.

GET /getAllArticles          # (X)
GET /getArticles?id=1        # (X)
POST /createArticles         # (X)
POST /updateArticle?id=1     # (X)
POST /deleteArticles?id=1    # (X)

4. 리소스 이름은 복수를 사용하며, 일관된 대소문자 규칙을 사용한다.

article 보다는 articles를 쓴다. 리소스와 필드 이름의 표기법을 통일한다. 스네이크 표기법(예: snake_case)이든, 낙타 표기법(예: camelCase)이든, 대시 표기법(예: dash-case)이든, 어떤 표기법이라도 상관없다. 단, 사용자의 예측 가능성을 위해서 일관되게 사용하자.

GET /articles                # (O)
GET /article                 # (X)
# 이름 표기법 혼용 사례

GET /push_messages            # URL에 스네이크 표기법 사용

{
  "total": 1540,
  "perPage": 10,              # URL에 낙타 표기법 사용
  "current-page": 1,          # URL에 대시 표기법 사용
  "data": ["..."]
}

5. 관계를 노출할 때는 리소스를 중첩한다.

GET /tags/{id}/articles             # (O)
GET /tags/1?sub_model=articles      # (X)

6. 컬렉션, 인스턴스 URL을 제외한 나머지 복잡함은 물음표(?) 뒤에서 표현한다.

GET /articles?q=Lorem                      # 검색
GET /articles?sort=view_count&order=asc    # 정렬
GET /articles?page=2                       # 페이징
GET /articles?fields=id,title              # 필드 선택

7. 알맞은 HTTP 응답 코드를 사용한다.

HTTP 응답 코드는 제각각 의미를 담고 있으므로 상황에 맞는 응답 코드를 사용해야 한다. 다음은 웹 API 에서 주로 사용하는 응답 코드다.

200 - Ok                        # 성공
201 - Created                   # 리로스 생성 성공
204 - No Content                # 리소스 삭제 성공 등에 주로 사용
304 - Not Modified              # 클라이언트에 캐시된 리소스 대비 서버 리소스의 변경이 없음
400 - Bad Request               # 클라이언트의 요청 오류
401 - Unauthorized              # 인증 필요(실제로는 Unauthenticated 의미)
403 - Forbidden                 # 권한 부족(실제로는 Unauthorized 의미)
404 - Not Found                 # 요청한 리소스가 없음
405 - Method Not Allowed        # 서버에 없는 URL 엔드포인트
406 - Not Acceptable            # Accept\* 요청 헤더를 수용할 수 없음
409 - Conflict                  # 기존 리소스와 충돌
410 - Gone                      # 리소스가 삭제됨
422 - Unprocessable Entity      # 유효성 검사 오류
429 - Too Many Requests         # 사용량 초과 오류
500 - Internal Server Error     # 서버에서 요청 처리 중 오류
503 - Service Unavailable       # 서버가 일시적으로 응답할 수 없음

클라이언트(개발자)가 이해할 수 있는 에러 메시지도 같이 담아 주는 것이 좋다.

POST /articles

{
  "errors": {
    "code": 429,
    "message": "too\_many\_requests"
  }
}

8. HATEOAS(Hypermedia as the Engine of Application State)

HTML은 메뉴나 링크로 다른 페이지로 이동할 수 있다. 반면, 데이터만 제공하는 API 응답을 받은 클라이언트는 어떤 다른 리소스가 있는지 알 수 없다. API 응답 데이터에 다른 리소스로 이동하는 URL 엔드포인트를 포함하는 것을 HATEOAS(Hypermedia as the Engine of Application State)라 한다.

GET /articles

{
  data: [
    {
      id: 1,
      title: "...",
      links: [
        rel: "self",
        href: "http://api.myapp.test:8000/v1/articles"
      ],
      user: {
        id: 5,
        name: "...",
        links: [
          rel: "self",
          href: "http://api.myapp.test:8000/v1/users/5"
        ]
      }
    },
    { ... }
  ]
}

9. API 버전

서버에 HTML 페이지를 배포하면, 사용자는 곧바로 최신 페이지를 볼 수 있다. 반면, API 서비스에는 클라이언트와 서버가 완전히 분리되어 있다. 서버측에서 API를 변경하면 클라이언트가 정상 동작한다고 보장할 수 없다. 서버는 클라이언트가 API를 어떻게 이용하고, 어떻게 구현했는지 알 수 없기 때문이다.

클라이언트가 새로운 API에 맞추어 코드를 수정하고 배포하려면 시간이 걸린다. 이 기간 동안 옛 API는 그대로 살려두고, 새로운 API는 새로운 URL 엔드포인트로 서비스해야 한다. 그러므로 처음부터 /v1/articles와 같이 엔드포인트를 만드는 것이 좋다.

GET http://api.myapp.test:8000/v1/articles        # (O)
GET http://myapp.test:8000/api/v1/articles        # (O)

10. 콘텐츠/언어 협상

클라이언트는 응답 받기를 원하는 본문의 본문 형식을 요청하고(Accept), 서버는 응답 하는 데이터 형식을 준다(Content-Type). 언어(한국어/영어 등)도 마찬가지다.

# 클라이언트 요청
GET /articles
Accept: application/json
Accept-Language: ko-KR

# 서버 응답
HTTP/1.1 200 OK
Content-Type: application/json

{"message": "환영합니다."}
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크