티스토리 뷰
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