REST란 무엇인가
REST의 기원
REST(Representational State Transfer)는 2000년 로이 필딩(Roy Fielding)의 박사 논문에서 처음 정의된 소프트웨어 아키텍처 스타일입니다. 필딩은 HTTP/1.1 명세의 주요 저자이기도 하며, REST는 웹의 기존 인프라(HTTP, URI, 콘텐츠 타입)를 그대로 활용하는 것이 핵심 아이디어입니다.
REST의 6가지 제약 조건
- 클라이언트-서버 분리: UI와 데이터 저장을 분리하여 독립적 발전 가능
- 무상태(Stateless): 각 요청이 필요한 모든 정보를 포함, 서버에 세션 상태 저장 안 함
- 캐시 가능(Cacheable): 응답에 캐시 가능 여부를 명시
- 계층형 시스템: 클라이언트는 중간 서버(로드밸런서, CDN)의 존재를 알 필요 없음
- 통일된 인터페이스(Uniform Interface): 일관된 규칙으로 리소스에 접근
- 주문형 코드(Code on Demand): (선택) 서버가 클라이언트에 실행 가능한 코드 전송
---
URI 설계 규칙
리소스 명명 원칙
URI는 리소스(명사)를 표현하며, 행위(동사)는 HTTP 메서드로 표현합니다.
``` ✅ 올바른 URI 설계: GET /api/users → 사용자 목록 조회 GET /api/users/123 → ID 123 사용자 조회 POST /api/users → 새 사용자 생성 PUT /api/users/123 → ID 123 사용자 전체 수정 PATCH /api/users/123 → ID 123 사용자 부분 수정 DELETE /api/users/123 → ID 123 사용자 삭제
❌ 잘못된 URI 설계: GET /api/getUsers → 동사 사용 ❌ POST /api/createUser → 동사 사용 ❌ GET /api/user/delete/123 → HTTP 메서드 무시 ❌ ```
URI 설계 규칙 상세
1. 복수형 명사 사용 ``` ✅ /api/users, /api/articles, /api/categories ❌ /api/user, /api/article ```
2. 계층 관계는 중첩 경로로 표현 ``` GET /api/users/123/orders → 사용자 123의 주문 목록 GET /api/users/123/orders/456 → 사용자 123의 주문 456 ``` 단, 중첩이 3단계 이상이면 복잡해지므로 쿼리 파라미터를 고려합니다.
3. 소문자 + 하이픈 사용 ``` ✅ /api/blog-posts, /api/user-profiles ❌ /api/blogPosts, /api/blog_posts ```
4. 파일 확장자 사용 금지 ``` ✅ Accept: application/json 헤더로 응답 형식 지정 ❌ /api/users.json, /api/users.xml ```
---
HTTP 메서드의 올바른 사용
메서드별 의미와 특성
| 메서드 | 용도 | 안전 | 멱등 | 요청 Body | |--------|------|------|------|-----------| | GET | 조회 | ✅ | ✅ | 없음 | | POST | 생성 | ❌ | ❌ | 있음 | | PUT | 전체 교체 | ❌ | ✅ | 있음 | | PATCH | 부분 수정 | ❌ | ❌ | 있음 | | DELETE | 삭제 | ❌ | ✅ | 없음/있음 |
안전(Safe): 서버 상태를 변경하지 않음 멱등(Idempotent): 같은 요청을 여러 번 보내도 결과가 동일
PUT vs PATCH
``` PUT /api/users/123 → 리소스 전체를 교체. 보내지 않은 필드는 null/기본값으로 초기화
PATCH /api/users/123 → 지정한 필드만 수정. 나머지 필드는 유지 ```
실무에서는 대부분의 수정 작업이 부분 수정이므로 PATCH를 더 자주 사용합니다.
---
HTTP 상태 코드 가이드
2xx — 성공
- 200 OK: 일반적 성공 (GET, PATCH, DELETE)
- 201 Created: 리소스 생성 성공 (POST). Location 헤더에 새 리소스 URI 포함
- 204 No Content: 성공했으나 응답 본문 없음 (DELETE 후)
3xx — 리다이렉션
- 301 Moved Permanently: URI가 영구적으로 변경됨
- 304 Not Modified: 캐시된 리소스가 아직 유효함 (조건부 GET)
4xx — 클라이언트 에러
- 400 Bad Request: 잘못된 요청 형식, 유효성 검사 실패
- 401 Unauthorized: 인증 필요 (토큰 없음 또는 만료)
- 403 Forbidden: 인증됐으나 권한 부족
- 404 Not Found: 리소스가 존재하지 않음
- 409 Conflict: 현재 리소스 상태와 충돌 (중복 생성 등)
- 422 Unprocessable Entity: 형식은 맞으나 의미적으로 처리 불가
- 429 Too Many Requests: 요청 속도 제한 초과
5xx — 서버 에러
- 500 Internal Server Error: 서버 내부 오류 (예상치 못한 예외)
- 502 Bad Gateway: 업스트림 서버 응답 오류
- 503 Service Unavailable: 서버 점검 또는 과부하
---
에러 응답 표준화
일관된 에러 응답 형식
```json { "error": { "code": "VALIDATION_ERROR", "message": "요청 데이터가 유효하지 않습니다.", "details": [ { "field": "email", "message": "유효한 이메일 주소를 입력해주세요." }, { "field": "age", "message": "나이는 0 이상이어야 합니다." } ] } } ```
에러 응답 설계 원칙
- 기계가 읽을 수 있는 코드: `VALIDATION_ERROR`, `NOT_FOUND` 등 열거형 코드
- 사람이 읽을 수 있는 메시지: 개발자가 이해할 수 있는 설명
- 필드별 상세 정보: 유효성 검사 실패 시 어떤 필드가 왜 실패했는지
- 보안 주의: 내부 스택 트레이스, DB 스키마 정보를 에러에 노출하지 않기
---
페이지네이션
오프셋 기반 페이지네이션
``` GET /api/articles?page=2&limit=20 ```
응답: ```json { "data": [...], "pagination": { "page": 2, "limit": 20, "total": 156, "totalPages": 8 } } ```
장점: 구현 간단, 임의 페이지 접근 가능 단점: 데이터 추가/삭제 시 누락·중복 발생 가능, 큰 오프셋에서 성능 저하
커서 기반 페이지네이션
``` GET /api/articles?cursor=eyJpZCI6MTAwfQ&limit=20 ```
응답: ```json { "data": [...], "pagination": { "nextCursor": "eyJpZCI6MTIwfQ", "hasMore": true } } ```
장점: 실시간 데이터에서 누락·중복 없음, 일관된 성능 단점: "N번째 페이지로 이동" 불가, 구현 복잡도 증가
실무 권장: 관리자 패널(표 형태) → 오프셋, 타임라인·피드(무한 스크롤) → 커서
---
API 버저닝
버저닝 전략 비교
1. URI 버저닝 (가장 흔함) ``` /api/v1/users /api/v2/users ``` 장점: 직관적, 브라우저에서 바로 테스트 가능 단점: URI가 변경되므로 REST 순수주의자가 반대
2. 헤더 버저닝 ``` GET /api/users Accept: application/vnd.myapp.v2+json ``` 장점: URI 깔끔 단점: 테스트가 어렵고, 캐싱 설정 복잡
3. 쿼리 파라미터 버저닝 ``` GET /api/users?version=2 ```
실무 권장: 대부분의 대규모 API(Google, GitHub, Stripe)가 URI 버저닝을 사용합니다. 단순하고 명확하다는 것이 가장 큰 장점입니다.
---
인증과 보안
JWT 기반 인증
현재 REST API에서 가장 널리 사용되는 인증 방식입니다.
``` Authorization: Bearer eyJhbGciOiJIUzI1NiIs... ```
Access Token + Refresh Token 패턴:
- Access Token: 짧은 만료 시간(15분~1시간), API 요청 시 사용
- Refresh Token: 긴 만료 시간(7~30일), Access Token 갱신 시 사용
- Refresh Token은 httpOnly 쿠키에 저장하여 XSS 방어
API 보안 체크리스트
- HTTPS 필수: 모든 API 통신은 TLS 암호화
- Rate Limiting: IP/사용자별 요청 속도 제한 (429 응답)
- 입력 검증: 서버 측에서 모든 입력 데이터 검증 (클라이언트 검증만으로 불충분)
- CORS 설정: 허용된 Origin만 API 접근 가능
- SQL Injection 방지: ORM 사용 또는 파라미터화된 쿼리
- 민감 데이터 마스킹: 로그에 비밀번호, 토큰 등 기록 금지
---
좋은 API 설계의 최종 체크리스트
- [ ] URI는 리소스(명사)를 표현하고, 행위는 HTTP 메서드로 표현
- [ ] 적절한 HTTP 상태 코드 사용 (200만 반환하지 않기)
- [ ] 일관된 에러 응답 형식 (code + message + details)
- [ ] 페이지네이션 제공 (대량 데이터 응답 방지)
- [ ] 버저닝 전략 적용
- [ ] HTTPS + 인증 + Rate Limiting 보안 적용
- [ ] API 문서화 (OpenAPI/Swagger) 제공
좋은 API는 예측 가능하고, 일관적이며, 자기 설명적입니다. 개발자가 문서를 최소한으로 참고하면서도 직관적으로 사용할 수 있어야 합니다.