AgentSkillsCN

api-design

REST API 设计原则、GraphQL 模式、API 版本控制

SKILL.md
--- frontmatter
name: api-design
description: REST API 설계 원칙, GraphQL 패턴, API 버저닝

API Design Guide

REST API 원칙

리소스 중심 URL

text
# Bad: 동사 중심
GET /getUsers
POST /createUser
PUT /updateUser/123
DELETE /deleteUser/123

# Good: 명사 중심 (리소스)
GET /users           # 목록 조회
GET /users/123       # 단일 조회
POST /users          # 생성
PUT /users/123       # 전체 수정
PATCH /users/123     # 부분 수정
DELETE /users/123    # 삭제

중첩 리소스

text
# 관계 표현
GET /users/123/posts         # 사용자의 게시물
GET /posts/456/comments      # 게시물의 댓글

# 깊은 중첩 피하기 (3단계 이상)
# Bad
GET /users/123/posts/456/comments/789/likes

# Good: 직접 접근
GET /comments/789/likes

HTTP 메서드 의미

메서드용도멱등성안전
GET조회OO
POST생성XX
PUT전체 수정OX
PATCH부분 수정XX
DELETE삭제OX

상태 코드

text
# 성공
200 OK           # 일반 성공
201 Created      # 리소스 생성 (POST 성공)
204 No Content   # 성공했지만 반환할 내용 없음 (DELETE)

# 클라이언트 에러
400 Bad Request      # 잘못된 요청
401 Unauthorized     # 인증 필요
403 Forbidden        # 권한 없음
404 Not Found        # 리소스 없음
409 Conflict         # 충돌 (중복 등)
422 Unprocessable    # 유효성 검증 실패

# 서버 에러
500 Internal Server Error  # 서버 오류
503 Service Unavailable    # 서비스 불가

응답 형식

성공 응답

json
// 단일 리소스
{
    "data": {
        "id": "123",
        "name": "John",
        "email": "john@example.com"
    }
}

// 목록 (페이지네이션)
{
    "data": [
        {"id": "1", "name": "John"},
        {"id": "2", "name": "Jane"}
    ],
    "pagination": {
        "page": 1,
        "perPage": 20,
        "total": 100,
        "totalPages": 5
    }
}

에러 응답

json
{
    "error": {
        "code": "VALIDATION_ERROR",
        "message": "Invalid input data",
        "details": [
            {
                "field": "email",
                "message": "Invalid email format"
            }
        ]
    }
}

페이지네이션

Offset 기반

text
GET /users?page=2&per_page=20

# 응답
{
    "data": [...],
    "pagination": {
        "page": 2,
        "per_page": 20,
        "total": 100
    }
}

Cursor 기반 (대용량)

text
GET /users?cursor=abc123&limit=20

# 응답
{
    "data": [...],
    "pagination": {
        "next_cursor": "def456",
        "has_more": true
    }
}

필터링, 정렬, 검색

text
# 필터링
GET /users?status=active&role=admin

# 정렬
GET /users?sort=created_at&order=desc
GET /users?sort=-created_at  # 축약형

# 검색
GET /users?q=john

# 필드 선택
GET /users?fields=id,name,email

# 복합 예시
GET /users?status=active&sort=-created_at&fields=id,name&page=1

API 버저닝

URL 버저닝 (권장)

text
GET /v1/users
GET /v2/users

헤더 버저닝

text
GET /users
Accept: application/vnd.api+json; version=2

버전 관리 전략

text
# v1 유지하면서 v2 추가
/v1/users  # 기존 (deprecated)
/v2/users  # 신규

# Breaking Change 예시
# v1: { "name": "John" }
# v2: { "firstName": "John", "lastName": "Doe" }

Rate Limiting

text
# 응답 헤더
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1640000000

# 429 응답 시
{
    "error": {
        "code": "RATE_LIMIT_EXCEEDED",
        "message": "Too many requests",
        "retry_after": 60
    }
}

인증

Bearer Token

text
Authorization: Bearer <token>

# 에러 응답
401 Unauthorized
{
    "error": {
        "code": "INVALID_TOKEN",
        "message": "Token expired or invalid"
    }
}

API Key

text
# 헤더
X-API-Key: <api_key>

# 또는 쿼리 파라미터 (비권장)
GET /users?api_key=<api_key>

API 문서화

OpenAPI (Swagger) 예시

yaml
openapi: 3.0.0
info:
  title: User API
  version: 1.0.0

paths:
  /users:
    get:
      summary: Get all users
      parameters:
        - name: page
          in: query
          schema:
            type: integer
            default: 1
      responses:
        200:
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserList'

API 설계 체크리스트

URL 설계

  • 리소스 중심 명사 사용
  • 복수형 사용 (/users, /posts)
  • 소문자, 하이픈 사용
  • 3단계 이상 중첩 피하기

응답 설계

  • 일관된 응답 구조
  • 적절한 상태 코드
  • 명확한 에러 메시지
  • 페이지네이션 정보 포함

보안

  • HTTPS 필수
  • 인증 구현
  • Rate Limiting
  • 입력 검증

문서화

  • OpenAPI/Swagger 문서
  • 예시 요청/응답
  • 에러 코드 목록
  • 변경 이력

관련 스킬

  • security: API 보안 취약점
  • documentation: API 문서 작성