REST 아키텍처 - 배경부터 핵심까지
TL;DR
- REST를 REST답게 만드는 핵심 제약조건.
- REST 아키텍처 - 배경부터 핵심까지를 알아두면 설계 판단과 구현 선택을 더 분명하게 할 수 있다.
- 원문 전체는 아래 상세 내용에 그대로 포함했다.
1. 개념
REST를 REST답게 만드는 핵심 제약조건.
2. 배경
REST, RESTful, Uniform Interface, Stateless, HATEOAS, Richardson 성숙도, HTTP 메서드, 리소스, 표현, 자기 서술적 메시지
3. 이유
REST 아키텍처 - 배경부터 핵심까지를 알아두면 설계 판단과 구현 선택을 더 분명하게 할 수 있다.
4. 특징
REST 아키텍처 - 배경부터 핵심까지의 특징, 장단점, 적용 포인트를 원문에서 자세히 확인할 수 있다.
5. 상세 내용
REST 아키텍처 - 배경부터 핵심까지
1. REST의 탄생 배경
1.1 REST 이전의 혼란
┌─────────────────────────────────────────────────────────────────┐
│ REST 이전의 혼란 │
│ │
│ 1990년대 후반 ~ 2000년대 초반 │
│ │
│ 웹 서비스 통신 방법들: │
│ ├── CORBA (1991): 복잡한 바이너리 프로토콜 │
│ ├── DCOM (1996): Windows 전용, 방화벽 문제 │
│ ├── RMI (1997): Java 전용 │
│ └── SOAP (1998): XML 기반, 엄청나게 복잡 │
│ │
│ SOAP 메시지 예시: │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ <?xml version="1.0"?> │ │
│ │ <soap:Envelope │ │
│ │ xmlns:soap="http://www.w3.org/2003/05/soap-envelope"> │ │
│ │ <soap:Header> │ │
│ │ <auth:Credentials>...</auth:Credentials> │ │
│ │ </soap:Header> │ │
│ │ <soap:Body> │ │
│ │ <m:GetUser> │ │
│ │ <m:UserId>123</m:UserId> │ │
│ │ </m:GetUser> │ │
│ │ </soap:Body> │ │
│ │ </soap:Envelope> │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ 문제점: │
│ ├── 너무 복잡하고 무거움 │
│ ├── WSDL (서비스 정의) 작성이 고통 │
│ ├── 모든 요청이 POST (HTTP를 단순 터널로만 사용) │
│ └── 디버깅 어려움 │
│ │
└─────────────────────────────────────────────────────────────────┘
1.2 Roy Fielding과 REST의 등장
┌─────────────────────────────────────────────────────────────────┐
│ REST의 탄생 (2000년) │
│ │
│ Roy Fielding: │
│ ├── HTTP/1.0, HTTP/1.1 명세 공동 저자 │
│ ├── Apache HTTP Server 공동 개발자 │
│ └── "웹이 왜 이렇게 잘 작동하는지" 분석 │
│ │
│ 2000년, UC Irvine 박사 논문: │
│ "Architectural Styles and the Design of │
│ Network-based Software Architectures" │
│ │
│ 핵심 통찰: │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ "웹(WWW)은 이미 거대하고 성공적인 분산 시스템이다. │ │
│ │ 웹이 성공한 아키텍처 원칙을 API에도 적용하자!" │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ REST = REpresentational State Transfer │
│ = 표현된 상태의 전송 │
│ = 리소스의 현재 상태를 표현해서 주고받자 │
│ │
└─────────────────────────────────────────────────────────────────┘
2. REST의 6가지 제약조건
┌─────────────────────────────────────────────────────────────────┐
│ REST의 6가지 아키텍처 제약조건 │
│ │
│ 1. Client-Server (클라이언트-서버 분리) │
│ 2. Stateless (무상태) │
│ 3. Cacheable (캐시 가능) │
│ 4. Uniform Interface (균일한 인터페이스) ← 가장 중요! │
│ 5. Layered System (계층화 시스템) │
│ 6. Code on Demand (선택적, 코드 전송) │
│ │
│ 이 6가지를 모두 지켜야 "RESTful" │
│ │
└─────────────────────────────────────────────────────────────────┘
2.1 Client-Server
┌─────────────────────────────────────────────────────────────────┐
│ 1. Client-Server 분리 │
│ │
│ ┌──────────┐ ┌──────────┐ │
│ │ Client │ ◄─── HTTP 요청/응답 ──► │ Server │ │
│ │ (UI) │ │ (Data) │ │
│ └──────────┘ └──────────┘ │
│ │
│ 핵심: │
│ ├── 관심사의 분리 (Separation of Concerns) │
│ ├── 클라이언트: UI, 사용자 경험 │
│ ├── 서버: 데이터 저장, 비즈니스 로직 │
│ └── 각각 독립적으로 발전 가능 │
│ │
│ 예: 모바일 앱 새 버전 출시해도 서버는 그대로 │
│ 서버 DB 교체해도 클라이언트는 모름 │
│ │
└─────────────────────────────────────────────────────────────────┘
2.2 Stateless (무상태)
┌─────────────────────────────────────────────────────────────────┐
│ 2. Stateless (무상태) │
│ │
│ "서버는 클라이언트의 상태를 기억하지 않는다" │
│ │
│ ❌ Stateful (상태 유지): │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 요청 1: "로그인해줘" (id=kim) │ │
│ │ 서버: "OK, 너를 기억할게" (세션 저장) │ │
│ │ │ │
│ │ 요청 2: "내 주문 목록 줘" │ │
│ │ 서버: "아까 kim이었지? 여기 있어" │ │
│ │ │ │
│ │ 문제: 서버 여러 대면? 다른 서버로 가면 모름! │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ✅ Stateless (무상태): │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 요청 1: "로그인" → 서버: "여기 토큰(JWT)" │ │
│ │ │ │
│ │ 요청 2: "내 주문 목록 줘" + 토큰 │ │
│ │ 서버: "토큰 확인, kim이구나, 여기 있어" │ │
│ │ │ │
│ │ 장점: 어떤 서버든 처리 가능! (확장성) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ 이점: │
│ ├── 서버 확장 쉬움 (로드밸런서 뒤에 서버 추가) │
│ ├── 서버 장애 시 다른 서버가 처리 │
│ └── 요청 간 의존성 없음 │
│ │
└─────────────────────────────────────────────────────────────────┘
2.3 Cacheable (캐시 가능)
┌─────────────────────────────────────────────────────────────────┐
│ 3. Cacheable (캐시 가능) │
│ │
│ "응답이 캐시 가능한지 명시해야 한다" │
│ │
│ ┌──────────┐ ┌───────┐ ┌──────────┐ │
│ │ Client │───►│ Cache │───►│ Server │ │
│ └──────────┘ └───────┘ └──────────┘ │
│ │ │
│ └── 캐시 히트 시 서버 안 감 │
│ │
│ HTTP 헤더로 캐시 제어: │
│ ├── Cache-Control: max-age=3600 (1시간 캐시) │
│ ├── ETag: "abc123" (버전 태그) │
│ └── Last-Modified: ... (마지막 수정 시간) │
│ │
│ GET /users/1 → 캐시 가능 (같은 요청 = 같은 응답) │
│ POST /users → 캐시 불가 (매번 다른 결과) │
│ │
│ 이점: 성능 향상, 서버 부하 감소 │
│ │
└─────────────────────────────────────────────────────────────────┘
2.4 Layered System (계층화)
┌─────────────────────────────────────────────────────────────────┐
│ 5. Layered System (계층화 시스템) │
│ │
│ "클라이언트는 중간 계층을 모른다" │
│ │
│ ┌──────────┐ ┌───────┐ ┌──────┐ ┌──────────┐ │
│ │ Client │──►│ CDN │──►│ LB │──►│ Server │ │
│ └──────────┘ └───────┘ └──────┘ └──────────┘ │
│ │ │ │
│ └─── 클라이언트는 그냥 요청만 보냄 ────┘ │
│ 중간에 뭐가 있는지 모름 │
│ │
│ 중간 계층 예시: │
│ ├── 로드 밸런서 │
│ ├── 캐시 서버 (Redis, Varnish) │
│ ├── API Gateway │
│ ├── 보안 프록시 │
│ └── CDN │
│ │
│ 이점: 보안, 확장성, 유연한 아키텍처 │
│ │
└─────────────────────────────────────────────────────────────────┘
2.5 Code on Demand (선택적)
┌─────────────────────────────────────────────────────────────────┐
│ 6. Code on Demand (선택적) │
│ │
│ "서버가 클라이언트에 실행 가능한 코드 전송" │
│ │
│ 예시: │
│ ├── JavaScript 전송 (웹 페이지) │
│ ├── Java Applet (옛날) │
│ └── Flash (RIP) │
│ │
│ 유일한 선택적 제약조건 │
│ 대부분의 REST API에서는 해당 없음 │
│ │
└─────────────────────────────────────────────────────────────────┘
3. Uniform Interface (균일한 인터페이스) - 가장 중요!
REST를 REST답게 만드는 핵심 제약조건. 4가지 하위 제약으로 구성됨.
┌─────────────────────────────────────────────────────────────────┐
│ Uniform Interface의 4가지 하위 제약 │
│ │
│ ① Identification of Resources (리소스 식별) │
│ ② Manipulation through Representations (표현을 통한 조작) │
│ ③ Self-descriptive Messages (자기 서술적 메시지) │
│ ④ HATEOAS (하이퍼미디어를 통한 상태 전이) │
│ │
│ 왜 중요한가? │
│ ├── 다른 제약은 다른 아키텍처도 가질 수 있음 │
│ ├── Uniform Interface가 REST를 REST답게 만드는 핵심 │
│ └── Roy Fielding: "REST의 핵심 특징" │
│ │
└─────────────────────────────────────────────────────────────────┘
3.1 리소스 식별 (Identification of Resources)
┌─────────────────────────────────────────────────────────────────┐
│ ① 리소스 식별 (Identification of Resources) │
│ │
│ 핵심: "모든 리소스는 고유한 URI로 식별된다" │
│ │
│ 리소스란? │
│ ├── 명사로 표현되는 "것" (noun) │
│ ├── 사용자, 주문, 상품, 댓글 등 │
│ └── 동사가 아닌 명사! │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ URI 설계 │ │
│ │ │ │
│ │ ❌ 나쁜 예 (동사 사용): │ │
│ │ POST /getUsers │ │
│ │ POST /createUser │ │
│ │ POST /deleteUser?id=123 │ │
│ │ GET /getUserOrders?userId=123 │ │
│ │ │ │
│ │ ✅ 좋은 예 (명사 + HTTP 메서드): │ │
│ │ GET /users → 사용자 목록 │ │
│ │ GET /users/123 → 123번 사용자 │ │
│ │ POST /users → 사용자 생성 │ │
│ │ DELETE /users/123 → 123번 사용자 삭제 │ │
│ │ GET /users/123/orders → 123번 사용자의 주문 목록 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ URI 설계 원칙: │
│ ├── 복수형 사용: /users (not /user) │
│ ├── 계층 관계 표현: /users/123/orders/456 │
│ ├── 소문자 사용: /users (not /Users) │
│ ├── 하이픈 사용: /user-profiles (not /user_profiles) │
│ └── 파일 확장자 없음: /users/123 (not /users/123.json) │
│ │
└─────────────────────────────────────────────────────────────────┘
3.2 표현을 통한 조작 (Manipulation through Representations)
┌─────────────────────────────────────────────────────────────────┐
│ ② 표현을 통한 조작 (Manipulation through Representations) │
│ │
│ 핵심: "리소스 자체가 아닌 '표현'을 주고받는다" │
│ │
│ 리소스 vs 표현: │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 리소스 (Resource): │ │
│ │ └── DB에 저장된 실제 데이터 │ │
│ │ └── users 테이블의 id=123 레코드 │ │
│ │ │ │
│ │ 표현 (Representation): │ │
│ │ └── 리소스의 현재 상태를 특정 형식으로 표현한 것 │ │
│ │ └── JSON, XML, HTML, 이미지 등 │ │
│ │ │ │
│ │ 같은 리소스, 다른 표현: │ │
│ │ GET /users/123 │ │
│ │ Accept: application/json → {"id":123, "name":"Kim"} │ │
│ │ Accept: application/xml → <user><id>123</id>...</user> │ │
│ │ Accept: text/html → <html>사용자 정보...</html> │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ 조작 예시: │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 1. 조회: 리소스의 "표현"을 받음 │ │
│ │ GET /users/123 │ │
│ │ 응답: {"id": 123, "name": "Kim", "email": "..."} │ │
│ │ │ │
│ │ 2. 수정: "표현"을 보내서 리소스 변경 │ │
│ │ PUT /users/123 │ │
│ │ Body: {"id": 123, "name": "Park", "email": "..."} │ │
│ │ → 서버가 이 표현으로 리소스를 업데이트 │ │
│ │ │ │
│ │ 3. 생성: "표현"을 보내서 새 리소스 생성 │ │
│ │ POST /users │ │
│ │ Body: {"name": "Lee", "email": "..."} │ │
│ │ → 서버가 이 표현으로 새 리소스 생성 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ 의미: │
│ ├── 클라이언트는 표현만 다루면 됨 (실제 저장 방식 몰라도 됨) │
│ ├── 서버 내부 구조가 변해도 표현이 같으면 클라이언트 수정 불필요│
│ └── 콘텐츠 협상 (Content Negotiation) 가능 │
│ │
└─────────────────────────────────────────────────────────────────┘
3.3 자기 서술적 메시지 (Self-descriptive Messages)
┌─────────────────────────────────────────────────────────────────┐
│ ③ 자기 서술적 메시지 (Self-descriptive Messages) │
│ │
│ 핵심: "메시지만 보고 무엇을 해야 하는지 완전히 알 수 있어야 함" │
│ │
│ ❌ 자기 서술적이지 않은 메시지: │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ GET /users/123 HTTP/1.1 │ │
│ │ Host: api.example.com │ │
│ │ │ │
│ │ 응답: │ │
│ │ HTTP/1.1 200 OK │ │
│ │ │ │
│ │ {"id": 123, "name": "Kim"} │ │
│ │ │ │
│ │ 문제: 이게 JSON인지 어떻게 알아? │ │
│ │ 이 숫자들의 의미는? │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ✅ 자기 서술적인 메시지: │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ GET /users/123 HTTP/1.1 │ │
│ │ Host: api.example.com │ │
│ │ Accept: application/json │ │
│ │ │ │
│ │ 응답: │ │
│ │ HTTP/1.1 200 OK │ │
│ │ Content-Type: application/json; charset=utf-8 │ │
│ │ Cache-Control: max-age=3600 │ │
│ │ ETag: "abc123" │ │
│ │ │ │
│ │ { │ │
│ │ "id": 123, │ │
│ │ "name": "Kim", │ │
│ │ "email": "kim@example.com" │ │
│ │ } │ │
│ │ │ │
│ │ 이제 알 수 있는 것: │ │
│ │ ├── 형식: JSON (Content-Type) │ │
│ │ ├── 캐시: 1시간 가능 (Cache-Control) │ │
│ │ ├── 버전: abc123 (ETag) │ │
│ │ └── 문자셋: UTF-8 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ 더 완벽한 자기 서술 (엄격한 해석): │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Content-Type: application/vnd.myapi.user+json; v=1 │ │
│ │ │ │
│ │ → 커스텀 미디어 타입으로 스키마 정보까지 포함 │ │
│ │ → 이 타입의 명세를 보면 필드 의미를 알 수 있음 │ │
│ │ → 현실에서는 거의 안 함 (OpenAPI/Swagger로 대체) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ 실무에서 자기 서술성: │
│ ├── Content-Type 필수 │
│ ├── 적절한 HTTP 상태 코드 사용 │
│ ├── 에러 응답에 명확한 메시지 포함 │
│ └── OpenAPI(Swagger) 문서로 보완 │
│ │
└─────────────────────────────────────────────────────────────────┘
HTTP 상태 코드로 자기 서술
┌─────────────────────────────────────────────────────────────────┐
│ HTTP 상태 코드 = 자기 서술 │
│ │
│ ┌──────────┬────────────────────────────────────────────────┐ │
│ │ 코드 │ 의미 (메시지 안 봐도 알 수 있음) │ │
│ ├──────────┼────────────────────────────────────────────────┤ │
│ │ 200 OK │ 성공 │ │
│ │ 201 Created│ 새 리소스 생성됨 │ │
│ │ 204 No Content│ 성공, 응답 본문 없음 │ │
│ │ 400 Bad Request│ 클라이언트 요청 오류 │ │
│ │ 401 Unauthorized│ 인증 필요 │ │
│ │ 403 Forbidden│ 권한 없음 │ │
│ │ 404 Not Found│ 리소스 없음 │ │
│ │ 409 Conflict│ 충돌 (중복 등) │ │
│ │ 422 Unprocessable│ 검증 실패 │ │
│ │ 500 Internal Error│ 서버 오류 │ │
│ └──────────┴────────────────────────────────────────────────┘ │
│ │
│ 상태 코드만 봐도 결과를 알 수 있다 = 자기 서술적 │
│ │
└─────────────────────────────────────────────────────────────────┘
3.4 HATEOAS (하이퍼미디어를 통한 상태 전이)
┌─────────────────────────────────────────────────────────────────┐
│ ④ HATEOAS (Hypermedia As The Engine Of Application State) │
│ │
│ 핵심: "응답에 다음에 할 수 있는 행동의 링크를 포함" │
│ │
│ 왜 필요한가? │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 일반 API (HATEOAS 없음): │ │
│ │ ───────────────────────── │ │
│ │ GET /users/123 │ │
│ │ 응답: {"id": 123, "name": "Kim"} │ │
│ │ │ │
│ │ 클라이언트: "이 사용자 삭제하려면 어디로 요청하지?" │ │
│ │ → 문서 보거나 코드에 하드코딩해야 함 │ │
│ │ → API 변경되면 클라이언트도 수정 필요 │ │
│ │ │ │
│ │ HATEOAS 적용: │ │
│ │ ───────────── │ │
│ │ GET /users/123 │ │
│ │ 응답: │ │
│ │ { │ │
│ │ "id": 123, │ │
│ │ "name": "Kim", │ │
│ │ "_links": { │ │
│ │ "self": {"href": "/users/123"}, │ │
│ │ "delete": {"href": "/users/123", "method": "DELETE"}│ │
│ │ "orders": {"href": "/users/123/orders"}, │ │
│ │ "update": {"href": "/users/123", "method": "PUT"} │ │
│ │ } │ │
│ │ } │ │
│ │ │ │
│ │ 클라이언트: 링크만 따라가면 됨! │ │
│ │ → URL 하드코딩 불필요 │ │
│ │ → API 변경되어도 링크만 따라가면 됨 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
HATEOAS 실제 예시
// 주문 조회 응답 (HATEOAS 적용)
{
"id": 456,
"status": "PENDING",
"total": 50000,
"items": [
{"productId": 1, "name": "키보드", "quantity": 1}
],
"_links": {
"self": {
"href": "/orders/456"
},
"cancel": {
"href": "/orders/456/cancel",
"method": "POST",
"title": "주문 취소"
},
"pay": {
"href": "/orders/456/payment",
"method": "POST",
"title": "결제하기"
},
"customer": {
"href": "/users/123"
}
}
}
// 주문 완료 후에는 cancel, pay 링크가 사라짐
{
"id": 456,
"status": "COMPLETED",
"total": 50000,
"_links": {
"self": {"href": "/orders/456"},
"receipt": {"href": "/orders/456/receipt"},
"refund": {"href": "/orders/456/refund", "method": "POST"}
}
}
HATEOAS의 현실
┌─────────────────────────────────────────────────────────────────┐
│ HATEOAS의 현실 │
│ │
│ 이상: │
│ ├── 클라이언트가 URL을 몰라도 됨 │
│ ├── 링크만 따라가면 모든 기능 사용 가능 │
│ ├── API 변경에 클라이언트가 자동 적응 │
│ └── 웹 브라우저처럼 동작! │
│ │
│ 현실: │
│ ├── 구현 복잡도 증가 │
│ ├── 응답 크기 증가 │
│ ├── 대부분의 클라이언트가 링크를 활용 안 함 │
│ ├── 프론트엔드 개발자: "그냥 URL 주세요" │
│ └── 거의 대부분 API가 HATEOAS 미적용 │
│ │
│ Roy Fielding의 불만: │
│ "HATEOAS 없으면 REST가 아니야!" │
│ → 그래서 대부분 "RESTful" (REST스러운)이라고 부름 │
│ │
│ 그래도 가치 있는 곳: │
│ ├── 공개 API (GitHub, Stripe 일부 적용) │
│ ├── 장기 유지보수 필요한 API │
│ └── 다양한 클라이언트 지원 필요 시 │
│ │
└─────────────────────────────────────────────────────────────────┘
4. Richardson 성숙도 모델
┌─────────────────────────────────────────────────────────────────┐
│ REST 성숙도 모델 (Richardson) │
│ │
│ Level 3: HATEOAS ← 진정한 REST │
│ (하이퍼미디어 컨트롤) (거의 없음) │
│ │ │
│ Level 2: HTTP Methods ← 대부분 여기 │
│ (GET, POST, PUT, DELETE) "RESTful API" │
│ │ │
│ Level 1: Resources ← 리소스 URI만 있음 │
│ (/users, /orders) │
│ │ │
│ Level 0: POX (Plain Old XML) ← SOAP 스타일 │
│ (하나의 엔드포인트에 모든 것) │
│ │
└─────────────────────────────────────────────────────────────────┘
각 레벨 예시
Level 0 (POX):
┌─────────────────────────────────────────────────────────────────┐
│ POST /api │
│ Body: {"action": "getUser", "userId": 123} │
│ │
│ POST /api │
│ Body: {"action": "createUser", "name": "Kim"} │
│ │
│ → 모든 요청이 같은 엔드포인트, action으로 구분 │
│ → RPC 스타일 │
└─────────────────────────────────────────────────────────────────┘
Level 1 (Resources):
┌─────────────────────────────────────────────────────────────────┐
│ POST /users/123 │
│ Body: {"action": "get"} │
│ │
│ POST /users │
│ Body: {"action": "create", "name": "Kim"} │
│ │
│ → 리소스 URI는 있지만, 여전히 POST만 사용 │
└─────────────────────────────────────────────────────────────────┘
Level 2 (HTTP Methods):
┌─────────────────────────────────────────────────────────────────┐
│ GET /users/123 │
│ POST /users Body: {"name": "Kim"} │
│ PUT /users/123 Body: {"name": "Park"} │
│ DELETE /users/123 │
│ │
│ → HTTP 메서드로 행위 표현 (대부분의 REST API) │
└─────────────────────────────────────────────────────────────────┘
Level 3 (HATEOAS):
┌─────────────────────────────────────────────────────────────────┐
│ GET /users/123 │
│ { │
│ "id": 123, "name": "Kim", │
│ "_links": { │
│ "self": {"href": "/users/123"}, │
│ "orders": {"href": "/users/123/orders"} │
│ } │
│ } │
│ │
│ → 응답에 다음 행동 링크 포함 (진정한 REST) │
└─────────────────────────────────────────────────────────────────┘
5. REST의 실질적 장점
┌─────────────────────────────────────────────────────────────────┐
│ REST가 주는 실질적 이점 │
│ │
│ 1. 단순함 │
│ ├── HTTP만 알면 됨 (이미 다 알고 있음) │
│ ├── WSDL, 복잡한 스펙 필요 없음 │
│ └── curl로 바로 테스트 가능 │
│ │
│ 2. 확장성 │
│ ├── Stateless → 서버 추가 쉬움 │
│ ├── 캐싱 → 부하 분산 │
│ └── 계층화 → 중간 서버 추가 쉬움 │
│ │
│ 3. 독립성 │
│ ├── 클라이언트/서버 독립 개발 │
│ ├── 언어/플랫폼 무관 │
│ └── 어떤 클라이언트든 같은 API 사용 │
│ │
│ 4. 가시성 │
│ ├── URL만 봐도 뭐하는지 알 수 있음 │
│ ├── GET /users/123 → 123번 사용자 조회 │
│ └── 디버깅 쉬움 │
│ │
│ 5. 웹 인프라 활용 │
│ ├── 기존 HTTP 캐시, 프록시, CDN 그대로 사용 │
│ └── 웹 생태계의 모든 도구 활용 가능 │
│ │
└─────────────────────────────────────────────────────────────────┘
6. 정리
┌─────────────────────────────────────────────────────────────────┐
│ REST 핵심 정리 │
│ │
│ REST의 본질: │
│ "웹이 성공한 아키텍처 원칙을 API에 적용하자" │
│ │
│ 6가지 제약조건: │
│ ├── 1. Client-Server: 관심사 분리 │
│ ├── 2. Stateless: 서버가 상태 안 기억 (확장성) │
│ ├── 3. Cacheable: 캐시 가능 (성능) │
│ ├── 4. Uniform Interface: 일관된 인터페이스 (핵심!) │
│ ├── 5. Layered System: 계층화 (유연성) │
│ └── 6. Code on Demand: 코드 전송 (선택적) │
│ │
│ Uniform Interface (가장 중요): │
│ ├── ① 리소스 식별: URI로 리소스 식별 (/users/123) │
│ ├── ② 표현으로 조작: JSON/XML로 상태 표현 │
│ ├── ③ 자기 서술적: 메시지만 보고 이해 가능 │
│ └── ④ HATEOAS: 응답에 다음 행동 링크 (거의 안 함) │
│ │
│ 현실: │
│ ├── 대부분 "Level 2 REST" (HTTP 메서드 활용) │
│ ├── HATEOAS까지 하는 곳 거의 없음 │
│ └── 그래도 SOAP보다 훨씬 나음! │
│ │
│ 핵심 가치: │
│ 단순함 + 확장성 + 웹 표준 활용 │
│ │
└─────────────────────────────────────────────────────────────────┘
관련 키워드
REST, RESTful, Uniform Interface, Stateless, HATEOAS, Richardson 성숙도, HTTP 메서드, 리소스, 표현, 자기 서술적 메시지