RESTful이란?

REST(Representational State Transfer)는 웹의 장점을 최대한 활용하는 API 설계 방식입니다. 2000년 Roy Fielding의 박사 논문에서 처음 소개되었으며, 현재 대부분의 웹 서비스에서 표준으로 사용됩니다.
REST가 필요한 이유
초기 웹 API들은 각자 다른 방식으로 설계되어 학습 비용이 높았습니다. 회원 조회를 위해 어떤 곳은 /getUserInfo를, 어떤 곳은 /member/get을 사용했죠. REST는 이런 혼란을 해결하기 위해 통일된 인터페이스를 제안했습니다.
📌 핵심 원칙
- 자원 중심: URL은 명사로 (동사 X)
- HTTP 메서드 활용: GET(조회), POST(생성), PUT(전체 수정), PATCH(부분 수정), DELETE(삭제)
- 무상태성: 각 요청은 독립적
- 일관된 인터페이스: 같은 패턴 반복
❌ 잘못된 설계 vs ✅ 올바른 설계
// ❌ 동사 중심의 잘못된 설계
POST /createMember
POST /getMemberInfo
POST /updateMemberInfo
POST /deleteMember
// ✅ RESTful 설계
POST /api/members // 생성
GET /api/members/{id} // 조회
PUT /api/members/{id} // 수정
DELETE /api/members/{id} // 삭제
예를 들어 잘못된 설계는 POST createMember, POST getMemberInfo, POST deleteMember 이런 식으로 URL에 동사를 넣습니다.
반면 RESTful 설계는 POST /api/members로 생성하고, GET /api/members로 조회하고, DELETE /api/members로 삭제합니다. URL은 members로 통일하고, 행위는 HTTP 메서드로 구분
이런식으로 작성되면 URL만 봐도 회원에 관한 API구나 바로 알 수 있습니다. 또한 모든 리소스에 같은 패턴을 적용할 수 있어서 일관성이 생깁니다
왜 올바른 설계인가?
- 직관적: URL만 봐도 무엇에 대한 것인지 파악 가능
- 일관성: 모든 리소스에 같은 패턴 적용
- 캐싱: GET 요청은 브라우저/CDN에서 자동 캐싱
실전 애매한 상황들
상황 1: 로그인/로그아웃
문제: 로그인은 자원이 아닌 행위인데, 어떻게 표현할까?
// ❌ 동사 사용
POST /login
POST /logout
// ✅ 세션을 자원으로 간주
POST /api/sessions // 로그인 (세션 생성)
DELETE /api/sessions/current // 로그아웃 (세션 삭제)
// ✅ 토큰을 자원으로
POST /api/auth/tokens // 토큰 발급
DELETE /api/auth/tokens // 토큰 삭제
해결 포인트: "로그인"을 "세션 생성"으로 재해석하면 RESTful하게 표현 가능
상황 2: 비밀번호 변경
// ❌ 동사 사용
POST /changePassword
// ✅ 서브 리소스로
PUT /api/members/{id}/password
POST /api/members/{id}/password/reset
상황 3: 복잡한 검색
문제: 검색 조건이 많아지면 URL이 너무 길어집니다.
// ✅ 간단한 검색 (조건 2-3개)
GET /api/members?name=홍길동&status=active
// ✅ 복잡한 검색 (조건 5개 이상)
POST /api/members/search
{
"filters": {
"name": "홍길동",
"ageRange": { "min": 20, "max": 30 },
"membershipTypes": ["premium", "vip"]
},
"page": 0,
"size": 20
}
선택 기준: 조건이 적으면 GET, 많거나 복잡하면 POST /search
상황 4: 일괄 처리
// ❌ 반복 호출
PATCH /api/reservations/1
PATCH /api/reservations/2
// ✅ 배치 처리
PATCH /api/reservations/batch
{
"ids": [1, 2, 3],
"updates": { "status": "approved" }
}
상황 5: 중첩된 관계
// ❌ 너무 깊은 중첩 (3단계 이상)
GET /api/gyms/{gymId}/branches/{branchId}/trainers/{trainerId}/reservations
// ✅ 최대 2단계 또는 쿼리 파라미터
GET /api/trainers/{trainerId}/reservations
GET /api/reservations?trainerId={trainerId}
원칙: 중첩은 최대 2단계까지만!
상황 6: 상태 변경
// ✅ 간단한 경우 - PATCH
PATCH /api/reservations/{id}
{ "status": "approved" }
// ✅ 복잡한 경우 - POST
POST /api/reservations/{id}/approval
{
"trainerId": "123",
"note": "승인합니다"
}
선택 기준: 단순 상태만 바꾸면 PATCH, 추가 데이터나 로직 있으면 POST
HTTP 상태 코드
성공 (2xx)
200 OK // 조회/수정 성공
201 Created // 생성 성공 (Location 헤더 포함)
204 No Content // 삭제 성공
202 Accepted // 비동기 처리
클라이언트 오류 (4xx)
400 Bad Request // 잘못된 요청
401 Unauthorized // 인증 필요
403 Forbidden // 권한 없음
404 Not Found // 자원 없음
409 Conflict // 중복
422 Unprocessable // 처리 불가능
서버 오류 (5xx)
500 Internal Server Error
503 Service Unavailable
실무 팁: 400과 422 구분이 애매하면 400 사용. 중요한 건 팀 내 일관성!
실전 필수 팁
1. 페이지네이션
데이터를 여러 페이지로 나눠서 조금씩 가져오는 것
왜 필요? 10,000개 데이터를 한번에 조회하면 서버 터짐!
GET /api/members?page=0&size=20&sort=createdAt,desc
// 응답
{
"content": [...], // 실제 데이터 20개
"totalElements": 500, // 전체 개수
"totalPages": 25, // 전체 페이지 수
"number": 0, // 현재 페이지
"first": true, // 첫 페이지 여부
"last": false // 마지막 페이지 여부
}
2. API 버저닝
API를 여러 버전으로 관리하는 것
왜 필요? 기존 API 변경 시 배포된 앱이 작동하지 않음
GET /api/v1/members // 기존 버전
GET /api/v2/members // 새 버전
언제 버전업?
- 응답 구조 변경
- 필수 파라미터 추가
- 기존 필드 삭제
3. 에러 응답 표준화
왜 필요? 프론트엔드가 에러를 화면에 표시하려면 일관된 형식 필요
{
"timestamp": "2024-01-01T10:00:00",
"status": 400,
"error": "Bad Request",
"message": "이메일 형식이 올바르지 않습니다",
"path": "/api/members",
"errors": [
{
"field": "email",
"message": "유효한 이메일을 입력하세요"
}
]
}
4. 자주 쓰는 쿼리 파라미터
?page=0&size=20 // 페이징
?sort=name,asc // 정렬
?status=active // 필터
?q=검색어 // 검색
?startDate=2024-01-01 // 날짜 범위
핵심 요약
애매한 상황 해결 공식
- 동사 필요시 → 자원으로 재해석 (로그인 → 세션)
- 복잡한 검색 → POST
/search - 일괄 처리 →
/batch - 깊은 중첩 → 쿼리 파라미터
- 상태 변경 → 간단하면 PATCH, 복잡하면 POST
실무 핵심 4가지
- 페이지네이션: 데이터 많으면 필수
- HTTP 상태 코드: 프론트와의 약속
- 에러 응답 표준화: 일관된 형식 유지
- 일관성: 완벽함보다 중요
'-- 오늘 있었던 개발 일기' 카테고리의 다른 글
| aws에 대해하여! (0) | 2026.01.06 |
|---|---|
| 2026년도 새해가 왔다 (0) | 2026.01.05 |
| MCP 연결에 대해! (0) | 2025.12.26 |
| Spring 프레임워크가 무엇인가 (0) | 2025.12.26 |
| NoSql에서 트랜잭션이 가능한가? (0) | 2025.12.22 |