REST는 Representational State Transfer의 약자로, 자원의 표현을 통해 상태를 전달한다는 의미를 가진 아키텍처 스타일입니다. 2000년에 로이 필딩(Roy Fielding) 박사가 자신의 박사 논문에서 처음 정의했습니다.
REST는 웹의 기존 기술(HTTP, URI, HTML 등)을 기반으로 한 네트워크 통신 설계 방식으로, 주로 클라이언트와 서버 간의 통신에 사용됩니다.
REST의 구성 요소는 다음과 같습니다.
- 자원(Resource): 서버가 관리하는 데이터 (예: 문서, 이미지, DB의 데이터 등)
- 표현(Representation): 자원을 표현하는 방식 (예: JSON, XML)
- 상태 전달(State Transfer): 클라이언트 요청 시, 자원의 상태를 클라이언트로 전달
REST는 하나의 설계 방식(Architectural Style)이지, 기술이나 프로토콜이 아닙니다.
REST의 핵심 목적
REST의 핵심은 두 가지로 요약됩니다.
- 리소스(Resource)를 고유한 URI로 식별
- 표준 HTTP 메서드(
GET, POST, PUT, PATCH, DELETE 등)를 사용하여 서버와 클라이언트가 상태를 주고받는 방식(CRUD 작업 수행)
REST의 6가지 원칙
| 원칙 | 개념 | 효과 | 예시 |
|---|
| Client-Server 구조 | 클라이언트는 UI, 서버는 로직 담당 | 관심사 분리 → 독립 개발 및 유지보수 용이 | React 프론트엔드 + Spring 백엔드 |
| Stateless (무상태성) | 요청 간 상태 정보 저장 안 함 | 확장성, 장애 대응력 향상 | 요청마다 access_token 포함 |
| Cacheable | 응답은 캐시 가능해야 함 | 성능 향상, 서버 부하 감소 | Cache-Control: max-age=60 |
| Uniform Interface (일관된 인터페이스) | 리소스 접근 방식 일관성 유지 | 문서 없이도 API 이해 가능 | /users/1 + JSON 응답 + Content-Type |
| Layered System (계층화 구조) | 중간 계층(프록시, 로드밸런서 등) 존재 가능 | 보안, 캐시, 로깅 등 기능 분리 | 프록시 → 캐시 → API 서버 순 요청 |
| Code on Demand (선택사항) | 서버가 코드(JS 등)를 전송하여 실행 가능 | 클라이언트 기능을 서버가 확장 | 서버가 JS 코드 전송 → Google Maps 렌더링 |
1. Client-Server 구조
개념
- 클라이언트와 서버의 관심사를 명확히 분리
- 클라이언트는 사용자 인터페이스(UI)를 담당
- 서버는 데이터 처리와 비즈니스 로직을 담당
- 서로의 역할이 명확히 분리되어야 함
효과
- 관심사 분리 → 독립적 개발 및 유지보수 용이
- 클라이언트와 서버를 따로 개발하거나 교체할 수 있음
예시
- 브라우저(React 앱)와 백엔드(Spring Boot API)는 서로 독립적으로 개발되며, REST API를 통해 데이터만 주고받는다.
2. Stateless (무상태성)
개념
- 서버는 클라이언트의 상태를 저장하지 않고 각 요청은 독립적
- 각 요청은 서로 독립적이야 하며, 요청에 필요한 모든 정보는 요청 안에 포함되어야 함
효과
- 서버가 확장하기 쉬움 (서버 간 상태 공유 필요 없음)
- 장애 발생 시 다른 서버로 요청을 넘기기 쉬움 (스케일 아웃 유리)
예시
- 클라이언트가 매번 access_token을 HTTP Header에 담아서 인증 요청을 보냄
→ 서버는 이전 요청을 기억하지 않고, 이 요청만 독립적으로 처리
3. Cacheable: 응답은 캐싱 가능해야 함 (HTTP의 Cache-Control 활용)
개념
- REST 응답은 HTTP의 캐시 메커니즘을 통해 재사용 가능해야 함
효과
- 불필요한 서버 처리 줄임 → 성능 향상
- 클라이언트, 프록시, CDN 등에서 응답을 재사용 가능
예시
/posts에 대한 GET 요청 결과가 자주 바뀌지 않는다면, 캐시 설정을 통해 60초 동안 응답을 재사용할 수 있도록 설정
Cache-Control: max-age=60
개념
- REST에서 가장 중요한 제약 조건
- 클라이언트와 서버가 서로 독립적으로 개발되어도 API를 일관되게 사용할 수 있어야 함
구성 요소 (4가지 규칙)
- 자원의 식별: URI를 통해 리소스 식별 (
/users/1)
- 표현을 통한 조작: 리소스는 JSON, XML 등의 형태로 표현
- 자기 서술적 메시지: 메시지 자체에 필요한 정보 포함 (예: Header에 Content-Type)
- 하이퍼미디어(HATEOAS): 응답에 다음 가능한 행동에 대한 링크 포함 (선택사항)
효과
- REST API 설계가 명확하고 일관성 있게 유지됨
- 클라이언트는 문서 없이도 API를 쉽게 사용할 수 있음
5. Layered System (계층화 구조): 서버는 여러 계층으로 구성 가능 (보안, 로드밸런싱 등)
개념
- 클라이언트는 자신이 요청을 보낸 서버가 실제 리소스를 처리하는 최종 서버인지, 중간 계층(예: 프록시, 로드밸런서 등)인지 알지 못한 채 요청을 전송합니다.
- API 서버는 여러 계층(보안, 로드밸런서, 프록시, 캐시 등)으로 구성될 수 있음
효과
- 보안, 로깅, 트래픽 분산, 캐싱 등을 각 계층에서 수행 가능
- 시스템 확장성과 안정성 증가
예시
- 사용자가 API 요청을 보내면, 프록시 서버 → 캐시 서버 → 인증 서버 → API 서버 순으로 요청을 전달하고 처리
6. Code on Demand (선택사항): 클라이언트가 서버로부터 코드를 받아 실행 가능 (예: JavaScript)
개념
- 서버가 클라이언트에게 코드(스크립트 등)를 전달해서, 클라이언트가 그 코드를 실행할 수 있게 하는 것
- 즉, 클라이언트가 단순히 데이터만 받는 게 아니라, 코드 자체도 받아서 실행할 수 있도록 하는 원칙
- 다른 원칙과 달리 선택사항
효과
- 클라이언트의 기능을 서버가 동적으로 확장 가능
예시
- 서버가 HTML과 함께 JavaScript 코드를 전송하여 클라이언트에서 동적으로 렌더링
- 예: Google Maps에서 서버가 JS 코드도 함께 내려보내 클라이언트에서 기능 실행 (확대/축소 등)
REST API의 구성 요소
1. 리소스 (Resource)
- URI로 식별되는 고유한 데이터 단위 (예: 사용자, 게시글, 상품 등)
- 주로 명사 형태로 표현하며, 각 리소스는 고유한 URI를 가짐
- 예:
/users, /posts/1, /products/42
2. 메서드 (Method)
- HTTP 동사로 리소스에 대해 어떤 동작(행위)을 할 것인지 지정
- 주요 메서드:
GET: 데이터 조회
POST: 새 리소스 생성
PUT: 리소스 전체 수정 (모든 필드를 새 값으로 덮어씀)
PATCH: 리소스 일부 수정 (특정 필드만 변경)
DELETE: 리소스 삭제
3. 표현 (Representation)
- 리소스는 다양한 형식으로 표현 가능
- REST API에서는 일반적으로 JSON을 사용하지만, XML, HTML, YAML 등도 사용 가능
- 표현은 요청과 응답의 Body에서 전달되며,
Content-Type과 Accept 헤더로 형식 지정
4. 상태 전이 (State Transfer)
- 클라이언트는 서버의 리소스 상태를 변경하기 위해 요청을 보냄
- 예: 사용자가
/posts/1에 PATCH 요청을 보내면, 해당 게시글의 일부 데이터(예: 제목)가 변경됨
- 이처럼 클라이언트가 상태를 바꾸기 위해 서버에 명시적으로 요청을 보내고, 서버는 그 결과를 응답으로 전달하는 과정을 상태 전이(State Transfer)라고 함
RESTful API란?
RESTful API는 REST 아키텍처의 원칙과 제약 조건을 올바르게 적용한 API를 의미합니다.
즉, 단순히 HTTP를 사용한다고 해서 RESTful한 것은 아니며, 다음과 같은 규칙을 지켜야 합니다.
RESTful API의 조건
REST API 사용 시 주의할 점
1. URI는 명사로, 동작은 HTTP 메서드로 표현
- URI는 리소스를 식별하는 역할만 해야 하며, 동사는 포함하지 않아야 함
- 잘못된 예: /getUser, /createPost
- 올바른 예: GET /users, POST /posts
- URI에 동작 이름을 붙이는 순간 RPC 스타일이 되며 REST 원칙에서 벗어남
RPC는 Remote Procedure Call의 약자로, 말 그대로 원격에서 함수를 호출하듯이 서버의 기능을 사용하는 방식을 의미함 (행위 중심, 동사를 URI에 적음)
2. 리소스는 복수형으로 표현
- REST에서는 리소스의 집합을 다루므로, 가능한 한 복수형 명사를 사용하는 것이 관례
- 예:
/users, /products, /orders
- 단수형 URI는 혼동을 줄 수 있음 (
/user vs /users)
3. HTTP 상태 코드를 정확하게 사용
- 응답에는 적절한 HTTP 상태 코드를 포함시켜야 클라이언트가 상황을 정확히 파악할 수 있음
- 예:
• 200 OK: 정상 응답
• 201 Created: 새 리소스 생성 완료
• 400 Bad Request: 잘못된 요청
• 404 Not Found: 리소스를 찾을 수 없음
• 500 Internal Server Error: 서버 내부 오류
4. GET 요청에는 Body를 사용하지 않음
- GET 요청은 데이터 조회용이며, Body를 사용하지 않아야 함
- 필요한 정보는 쿼리 파라미터로 전달
- 예: GET /search?q=rest
5. PUT과 PATCH의 차이를 명확히 구분
- PUT: 전체 리소스를 교체
- PATCH: 일부 필드만 수정
- 목적이 다르므로 무분별하게 혼용하면 API의 의미가 불명확해짐
6. URI에 동사를 넣지 말고, 행위는 메서드로 분리
POST /users/1/activate ❌ → 비RESTful
PATCH /users/1 + { "active": true } ✅ → RESTful
- 상태 변화는 URI로 표현하지 말고, 메서드와 바디로 전달
7. 리소스 간 관계 표현 시 URI 구조에 주의
- 중첩된 자원은 계층 구조로 표현하되, 과도한 깊이는 피해야 함
- 예: /users/1/orders (사용자 1의 주문 목록)
- 과도한 중첩 예: /users/1/orders/5/items/3/details
8. 버전 관리를 미리 고려
- API는 시간이 지남에 따라 변경되므로, 버전 관리 전략을 미리 세워야 함
- URL 버전링 (버전을 URL에 직접 명시하는 방식): /api/v1/users
- 헤더 기반 버전링 (요청 헤더에 버전 정보를 담는 방식): Accept: application/vnd.myapi.v1+json
→ Accept는 어떤 형식의 응답을 받고 싶다는 의미
→ MIME 타입의 일부로 버전 정보를 포함해서 서버에게 전달함
→ 즉. 서버는 헤더를 보고 V1으로 응답할지, V2로 응답할지 결정함
9. 정해진 포맷과 명세를 일관되게 유지
- 클라이언트-서버 간 통신을 명확하게 하기 위해, 요청과 응답 구조를 일관되게 유지
- 예: 모든 응답은 { status, data, error } 구조로 반환
10. 문서화는 선택이 아닌 필수
- REST API는 직관적이지만, 사용법과 요청/응답 스펙은 반드시 명세화해야 함
- Swagger(OpenAPI), Postman, Notion 등을 활용해 API 문서 제공
표: 예시로 이해하기
| 작업 | HTTP 메서드 | URI | 의미 |
|---|
| 전체 사용자 조회 | GET | /users | 사용자 목록 요청 |
| 특정 사용자 조회 | GET | /users/1 | 특정 사용자 정보 요청 |
| 사용자 생성 | POST | /users | 새 사용자 생성 |
| 사용자 수정 | PUT/PATCH | /users/1 | 사용자 정보 전체/일부 수정 |
| 사용자 삭제 | DELETE | /users/1 | 사용자 정보 삭제 |
REST의 장점
-
구조가 명확하고 직관적
- URI와 HTTP 메서드만 봐도 어떤 동작을 수행하는지 쉽게 유추할 수 있음
- 예:
GET /products/10 → 상품 10번 정보를 조회한다는 의미를 바로 알 수 있음
- 문서가 없어도 기본적인 사용법을 파악하기 쉬움
-
HTTP 표준 활용
- HTTP의 기본 기능(메서드, URI, 상태 코드, 헤더, 캐시 등)을 그대로 사용하므로
- 기존의 웹 인프라(브라우저, 프록시, 로드밸런서, 보안 장비 등)와 높은 호환성 제공
- 예:
304 Not Modified, 401 Unauthorized, Cache-Control 등 HTTP 표준 응답을 그대로 사용 가능
-
확장성과 유연성
- 클라이언트와 서버가 서로 독립적으로 개발되고 배포될 수 있음
- 서버의 기술 스택 변경이나 데이터베이스 변경이 클라이언트에 영향을 주지 않음
- 예: 프론트엔드는 React, 백엔드는 Spring Boot로 구성해도 REST API로 연결 가능
-
언어와 플랫폼 독립적
- REST는 HTTP 기반이므로, 어떤 언어나 플랫폼에서도 동일한 방식으로 요청/응답 처리 가능
- 예: Python, Java, JavaScript, Go, Node.js 등 모든 언어에서 REST API 호출 가능
- 다양한 디바이스(웹, 모바일, IoT 등)에서도 동일한 방식으로 API 사용 가능