Home API Design Overview
Post
Cancel

API Design Overview

API Design

목차

Resource와 endpoint

API 설계에서 resource는 클라이언트가 다루는 대상이다. 사용자, 주문, 상품, 댓글 같은 개념이 resource가 될 수 있다. endpoint는 그 resource에 접근하는 URL 경로다.

1
2
resource  User
endpoint  /users

resource 중심 설계는 동작 이름보다 대상을 중심으로 URL을 잡는 방식이다.

1
2
3
GET /users/1
POST /users
GET /orders?userId=1

다음처럼 동사를 URL에 과도하게 넣는 방식은 일관성이 약해질 수 있다.

1
2
POST /createUser
POST /deleteUser

물론 모든 API가 완벽히 REST 형태일 필요는 없다. 중요한 것은 클라이언트가 예측할 수 있는 규칙을 유지하는 것이다.

HTTP method

HTTP method는 resource에 어떤 행동을 할지 나타낸다.

1
2
3
4
5
GET     조회
POST    생성 또는 명령성 작업
PUT     전체 교체
PATCH   부분 수정
DELETE  삭제

POST, PUT, PATCH는 자주 헷갈린다.

1
2
3
POST   새 resource 생성 또는 처리 요청
PUT    resource 전체를 주어진 표현으로 교체
PATCH  resource 일부 필드만 수정

예시는 다음과 같다.

1
POST /users
1
2
3
{
  "name": "shin"
}
1
PATCH /users/1
1
2
3
{
  "name": "kim"
}

method 선택은 캐싱, 재시도, idempotency와도 연결된다. 예를 들어 GET은 서버 상태를 바꾸지 않아야 한다.

status code

HTTP status code는 요청 처리 결과를 숫자로 표현한다.

1
2
3
4
2xx  성공
3xx  리다이렉션
4xx  클라이언트 오류
5xx  서버 오류

자주 쓰는 코드는 다음과 같다.

1
2
3
4
5
6
7
8
9
200 OK                  요청 성공
201 Created             생성 성공
204 No Content          성공했지만 응답 본문 없음
400 Bad Request         요청 형식 오류
401 Unauthorized        인증 필요 또는 실패
403 Forbidden           권한 없음
404 Not Found           resource 없음
409 Conflict            현재 상태와 충돌
500 Internal Server Error 서버 내부 오류

상태 코드는 클라이언트가 다음 행동을 결정하는 데 중요하다. 예를 들어 401이면 로그인 또는 토큰 갱신이 필요하고, 403이면 로그인해도 권한이 없다는 의미에 가깝다.

request/response schema

schema는 요청과 응답의 데이터 구조 계약이다. 좋은 API는 필드 이름, 타입, 필수 여부, 에러 형식을 일관되게 유지한다.

1
2
3
4
5
{
  "id": 1,
  "name": "shin",
  "email": "shin@example.com"
}

에러 응답도 통일하는 것이 좋다.

1
2
3
4
5
{
  "code": "USER_NOT_FOUND",
  "message": "User not found",
  "requestId": "abc-123"
}

에러 응답 형식이 매번 다르면 클라이언트가 예외 처리를 안정적으로 하기 어렵다.

1
2
3
4
5
좋은 schema
-> 예측 가능
-> 문서화 가능
-> 테스트 가능
-> 클라이언트 구현 단순화

pagination

pagination은 많은 목록 데이터를 나누어 가져오는 방식이다. 대표적으로 offset pagination과 cursor pagination이 있다.

offset 방식은 페이지 번호나 시작 위치를 기준으로 한다.

1
GET /users?offset=20&limit=10

장점은 단순하다는 것이다. 단점은 데이터가 계속 추가/삭제되는 상황에서 중복이나 누락이 생길 수 있고, offset이 커지면 성능이 나빠질 수 있다는 점이다.

cursor 방식은 마지막으로 본 항목의 기준값을 다음 요청에 전달한다.

1
GET /users?cursor=eyJpZCI6MjAxfQ&limit=10

cursor 방식은 무한 스크롤, 실시간으로 변하는 목록에 더 적합한 경우가 많다.

1
2
offset  단순한 관리자 목록, 작은 데이터
cursor  큰 데이터, 무한 스크롤, 자주 변하는 목록

versioning

versioning은 API 계약을 변경할 때 기존 클라이언트를 보호하기 위한 전략이다.

1
2
GET /v1/users/1
GET /v2/users/1

API는 한번 공개되면 여러 클라이언트가 의존한다. 필드를 갑자기 삭제하거나 의미를 바꾸면 기존 앱이 깨질 수 있다.

변경은 크게 두 종류로 나눌 수 있다.

1
2
호환 변경     새 optional 필드 추가
비호환 변경   필드 삭제, 타입 변경, 의미 변경

versioning은 비호환 변경을 안전하게 도입하기 위한 방법이다. 다만 버전이 많아지면 서버 유지 비용이 증가한다.

좋은 API 변경 전략은 다음과 같다.

1
2
3
4
기존 응답 필드의 의미를 함부로 바꾸지 않기
새 필드는 가능하면 optional로 추가하기
비호환 변경은 새 version으로 제공하기
deprecated 기간을 명확히 두기
This post is licensed under CC BY 4.0 by the author.