API 디자인
AI 도움으로 API를 설계하는 방법을 배웁니다. RESTful API 설계 원칙과 실전 팁을 알아봅니다.
개요
좋은 API 설계는 개발자 경험을 좌우합니다. AI를 활용하여 일관되고 사용하기 쉬운 API를 설계할 수 있습니다.
- 자원의 명사 사용: /users, /posts
- HTTP 메서드 적절히 사용: GET, POST, PUT, DELETE
- 계층적 URL: /users/123/posts
- 일관된 응답 형식: JSON
- 무상태 (Stateless): 각 요청이 독립적
- 클라이언트-서버 분리: 관심사 분리
HTTP 메서드 이해하기
각 HTTP 메서드의 특성을 이해하고 올바르게 사용하는 것이 RESTful API의 핵심입니다.
| 메서드 | 용도 | 멱등성 | 안전성 | 예시 |
|---|---|---|---|---|
| GET | 리소스 조회 | ✅ O | ✅ O | GET /users/123 |
| POST | 리소스 생성 | ❌ X | ❌ X | POST /users |
| PUT | 리소스 전체 수정/생성 | ✅ O | ❌ X | PUT /users/123 |
| PATCH | 리소스 부분 수정 | △ 경우에 따라 | ❌ X | PATCH /users/123 |
| DELETE | 리소스 삭제 | ✅ O | ❌ X | DELETE /users/123 |
- 멱등성: 같은 요청을 여러 번 보내도 결과가 동일 (서버 상태가 같음)
- 안전성: 서버의 상태를 절대 변경하지 않음 (읽기 전용)
⚠️ 실무 주의사항: GET 요청에 데이터 변경 로직을 넣으면 안 됩니다!
API 유형
프로젝트에 맞는 API 유형을 선택하세요.
- REST API: 가장 널리 사용, HTTP 캐시 활용
- GraphQL: 클라이언트가 원하는 데이터 선택, Over-fetching 방지
- gRPC: 고성능, Protocol Buffers, 마이크로서비스
- WebSocket: 실시간 양방향 통신
- Webhook: 이벤트 기반 알림
- 단순 CRUD: REST API
- 복잡한 데이터 관계: GraphQL
- 실시간 업데이트: WebSocket
- 마이크로서비스: gRPC
엔드포인트 설계
API 엔드포인트를 설계합니다. 자원과 행동을 명확히 분리하면 일관된 API를 만들 수 있습니다.
엔드포인트 설계 요청
블로그 API의 엔드포인트를 설계해줘.
리소스:
- 사용자 (users)
- 게시물 (posts)
- 댓글 (comments)
- 카테고리 (categories)
요구:
- CRUD 엔드포인트
- 페이지네이션
- 필터링
- 정렬
명명 규칙
일관된 명명 규칙을 적용하세요.
RESTful 명명 규칙을 적용한 엔드포인트를 작성해줘:
리소스: orders (주문)
기본 CRUD:
- GET /orders # 전체 조회
- GET /orders/:id # 단일 조회
- POST /orders # 생성
- PUT /orders/:id # 전체 수정
- PATCH /orders/:id # 부분 수정
- DELETE /orders/:id # 삭제
특정 행동:
- POST /orders/:id/cancel # 주문 취소
- POST /orders/:id/refund # 환불 요청
관계 리소스:
- GET /orders/:id/items # 주문 상품 목록
- GET /users/:id/orders # 사용자의 주문 목록
쿼리 파라미터
필터링, 정렬, 페이지네이션을 위한 표준 파라미터를 정의하세요.
쿼리 파라미터 표준을 설계해줘:
페이지네이션:
- page: 페이지 번호 (기본값 1)
- limit: 페이지당 항목 수 (기본값 20, 최대 100)
- 예: /posts?page=2&limit=10
필터링:
- 필드명=값 형식
- 여러 필터: &로 연결
- 예: /posts?status=published&author_id=1
정렬:
- sort: 필드명
- order: asc | desc
- 예: /posts?sort=created_at&order=desc
검색:
- q: 검색어
- 예: /posts?q=안녕하세요
REST vs GraphQL
| 기준 | REST | GraphQL |
|---|---|---|
| 데이터_fetching | 엔드포인트당 고정 | 클라이언트가 선택 |
| Over-fetching | 많을 수 있음 | 없음 |
| 캐시 | HTTP 캐시 활용 | 커스텀 필요 |
| 학습 곡선 | 낮음 | 보통 |
요청/응답 형식
API 요청과 응답의 형식을 정의합니다. 일관된 형식은 개발자 경험을 크게 향상시킵니다.
응답 형식 요청
API 응답 형식을 표준화해줘.
성공 응답:
- success: boolean
- data: object
- message: string (선택)
- pagination: object (선택)
에러 응답:
- success: false
- error: object
- code: string
- message: string
- details: object (선택)
성공 응답 예시
{
"success": true,
"data": {
"id": 1,
"title": "첫 번째 게시물",
"content": "내용...",
"author": {
"id": 1,
"name": "홍길동"
},
"createdAt": "2024-01-15T10:30:00Z"
}
}
{
"success": true,
"data": [
{ "id": 1, "title": "게시물 1" },
{ "id": 2, "title": "게시물 2" }
],
"pagination": {
"page": 1,
"limit": 10,
"total": 100,
"totalPages": 10
}
}
에러 응답 예시
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "입력 데이터가 유효하지 않습니다",
"details": [
{ "field": "email", "message": "올바른 이메일을 입력해주세요" },
{ "field": "password", "message": "비밀번호는 8자 이상이어야 합니다" }
]
}
}
요청 본문Validation
사용자 생성 API의 요청 스키마를 작성해줘:
요구사항:
- email: 필수, 유효한 이메일 형식
- password: 필수, 8~20자, 영문+숫자+특수문자
- name: 필수, 2~50자
- age: 선택, 1~150 사이의 숫자
- role: 선택, 기본값 'user', enum ['user', 'admin']
도구: Zod 스키마로
에러 처리
일관된 에러 처리는 문제 진단과 디버깅을 쉽게 만듭니다.
HTTP 상태 코드
| 코드 | 의미 | 사용 상황 |
|---|---|---|
| 200 | OK | 성공적인 GET, PUT |
| 201 | Created | 리소스 생성 성공 |
| 204 | No Content | DELETE 성공, 응답 본문 없음 |
| 400 | Bad Request | 잘못된 요청 구문 |
| 401 | Unauthorized | 인증 필요 |
| 403 | Forbidden | 권한 없음 |
| 404 | Not Found | 리소스 없음 |
| 409 | Conflict | 데이터 충돌 (중복 등) |
| 422 | Unprocessable Entity | 유효성 검사 실패 |
| 429 | Too Many Requests | Rate Limit 초과 |
| 500 | Server Error | 서버 내부 오류 |
| 503 | Service Unavailable | 서비스 일시 중단 |
에러 코드 시스템
API 에러 코드 시스템을 설계해줘:
카테고리:
- AUTH_*: 인증/인가 관련
- VALIDATION_*: 유효성 검사
- RESOURCE_*: 리소스 관련
- INTERNAL_*: 서버 내부
예시:
- AUTH_TOKEN_EXPIRED
- AUTH_INVALID_CREDENTIALS
- VALIDATION_EMAIL_INVALID
- RESOURCE_NOT_FOUND
- RESOURCE_ALREADY_EXISTS
에러 처리 베스트 프랙티스
- 일관성: 모든 에러 응답 동일한 구조
- 정보 제공: 디버깅에 필요한 정보 포함
- 보안: 민감한 정보는 제외
- 로깅: 서버 측 에러는 반드시 로깅
API 버전 관리
API 버전을 관리하는 전략입니다. 클라이언트에게 호환성을 유지하면서 API를 발전시킬 수 있습니다.
버전 관리 요청
API 버전 관리 전략을 설계해줘.
요구사항:
1. URL 기반 버전 (v1, v2)
2. 호환성이 깨진 변경은 새 버전에서
3.이전 버전은 최소 6개월 지원
4. deprecation 알림 헤더
버전 관리 전략 비교
| 전략 | 장점 | 단점 |
|---|---|---|
| URL 경로 (v1/users) | 명확함, 캐시 용이 | 코드 중복 가능성 |
| 헤더 (Accept: v1+json) | URL 간결 | 캐시 어려움 |
| 쿼리 파라미터 (?version=1) | 간편함 | 캐시 어려움 |
Deprecation 정책
Deprecation: true
Link: <https://api.example.com/v2/users>; rel="successor-version"
Sunset: Sat, 01 Jun 2024 00:00:00 GMT
- 추가만: 기존 필드 제거 금지
- 필드명 변경: 새 필드 추가, 기존 필드 비권장 처리
- 응답 형식: 기존 구조 유지
- 기능 제거: Deprecation 기간 후에만
API 문서화
API 문서를 자동으로 생성합니다. 좋은 문서는 개발자 경험의 핵심입니다.
문서 생성 요청
OpenAPI (Swagger) 문서를 생성해줘.
포함 내용:
- 모든 엔드포인트 설명
- 요청/응답 스키마
- 에러 응답 예시
- 인증 요구사항
OpenAPI 스키마 예시
OpenAPI 3.0 스키마를 작성해줘:
엔드포인트: POST /api/users
요청:
- email: string, required, format email
- password: string, required, minLength 8
- name: string, required
응답:
- 201: user object
- 400: validation error
- 409: duplicate email error
스키마:
- components/schemas/User
- components/schemas/Error
- components/securitySchemes/BearerAuth
인증 및 권한
API 인증 및 권한 관리를 설계합니다.
인증 전략
| 방식 | 장점 | 사용 상황 |
|---|---|---|
| JWT | 무상태, 확장성 | 모바일, SPA |
| OAuth 2.0 | 타사 인증 가능 | 소셜 로그인 |
| API Key | 단순함 | 서버 간 통신 |
| Session | 서버 통제 | 전통적 웹 앱 |
인증 구현 요청
JWT 인증 시스템을 설계해줘:
요구사항:
- Access Token: 15분 유효
- Refresh Token: 7일 유효
- 저장소: httpOnly Cookie
- 보안: httpOnly, secure, sameSite
- 갱신 엔드포인트 포함
환경: Express.js + TypeScript
CORS 보안 설정
Cross-Origin Resource Sharing(CORS)는 웹 브라우저에서 다른 도메인의 리소스에 접근할 수 있도록 허용하는 메커니즘입니다.
app.use(cors())는 모든 도메인에서의 요청을 허용합니다.
프로덕션 환경에서는 절대 사용하면 안 됩니다!
- 악의적인 웹사이트에서 API 호출 가능
- 사용자 데이터 유출 위험
- CSRF(Cross-Site Request Forgery) 공격 가능
개발 환경: 모든 도메인 허용
const express = require('express');
const cors = require('cors');
const app = express();
// 개발 환경에서만 사용!
app.use(cors());
프로덕션 환경: 특정 도메인만 허용
const corsOptions = {
origin: [
'https://myapp.com',
'https://www.myapp.com',
'https://admin.myapp.com'
],
methods: ['GET', 'POST', 'PUT', 'DELETE'],
credentials: true, // 쿠키 포함 허용
maxAge: 86400 // preflight 캐시 시간 (24시간)
};
app.use(cors(corsOptions));
동적 Origin 검증
const allowedOrigins = process.env.NODE_ENV === 'production'
? ['https://myapp.com', 'https://www.myapp.com']
: ['http://localhost:3000', 'http://localhost:5173'];
const corsOptions = {
origin: (origin, callback) => {
// origin이 없는 경우 허용 (같은 도메인 요청, Postman 등)
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
}
},
credentials: true
};
app.use(cors(corsOptions));
환경 변수 활용
NODE_ENV=production
ALLOWED_ORIGINS=https://myapp.com,https://www.myapp.com
const allowedOrigins = process.env.ALLOWED_ORIGINS
? process.env.ALLOWED_ORIGINS.split(',')
: ['http://localhost:3000'];
const corsOptions = {
origin: allowedOrigins,
credentials: true
};
app.use(cors(corsOptions));
- 브라우저 개발자 도구: Console에서 CORS 에러 메시지 확인
- Preflight 요청: OPTIONS 메서드 요청이 성공하는지 확인
- 응답 헤더:
Access-Control-Allow-Origin헤더가 올바른지 확인 - Credentials: 쿠키를 사용한다면
credentials: true필수
CORS 테스트
# Preflight 요청 테스트
curl -X OPTIONS http://localhost:3000/api/users \
-H "Origin: https://myapp.com" \
-H "Access-Control-Request-Method: POST" \
-v
# 실제 요청 테스트
curl -X GET http://localhost:3000/api/users \
-H "Origin: https://myapp.com" \
-v
Rate Limiting
API 요청 제한을 설계합니다.
Rate Limit 요청
Rate Limiting 전략을 설계해줘:
요구사항:
- 일반 사용자: 100 req/min
- 프리미엄 사용자: 1000 req/min
- 특정 엔드포인트: 별도 제한
- Rate Limit 헤더 포함
헤더:
- X-RateLimit-Limit
- X-RateLimit-Remaining
- X-RateLimit-Reset
환경: Express.js
캐싱 전략
API 응답 캐싱을 설계합니다.
캐싱 전략
- CDN: 정적 자산, 공개 데이터
- API Gateway: 응답 캐싱
- 애플리케이션:Redis 활용
- HTTP 캐시: ETags, Last-Modified
캐싱 전략을 설계해줘:
시나리오:
- 사용자 프로필: 5분 캐시
- 상품 목록: 1분 캐시
- 실시간 재고: 캐시 안 함
- 인기 검색어: 10분 캐시
요구사항:
- Redis 사용
- Cache-Control 헤더
- Invalidation 전략
다음 단계
API 개발에 대해 더 자세히 배워보세요!
핵심 정리
- 엔드포인트: 리소스 기반 URL 설계
- 응답 형식: 일관된 JSON 구조
- 에러 처리: 적절한 HTTP 상태 코드
- 버전 관리: URL 기반 버전 관리
- 문서화: OpenAPI/Swagger