RESTful API(Representational State Transfer API)
REST는 2000년 로이 필딩(Roy Fielding)이 그의 박사 논문에서 처음 제시한 소프트웨어 아키텍처 스타일이다.
필딩은 HTTP의 주요 설계자 중 한 명으로, 웹의 기본 아키텍처를 정의하는 과정에서 REST 원칙을 발전시켰다.
REST는 네트워크 시스템, 특히 웹에서 자원을 정의하고 접근하는 방법을 제공한다. 그 이름에서 알 수 있듯이 핵심은 “표현(Representation)“과 “상태 전이(State Transfer)“이다.
- 표현(Representation): 자원(Resource)의 특정 시점 상태를 표현한 정보이다. 이는 JSON, XML, HTML 등 다양한 형식으로 나타낼 수 있다.
- 상태 전이(State Transfer): 클라이언트가 서버와 통신하며 자원의 상태를 변경하는 과정이다.
RESTful API는 웹의 기본 아키텍처를 활용하여 분산 시스템에서 자원에 접근하고 조작하는 일관된 방법을 제공한다.
제약 조건을 준수할수록 확장성, 유연성, 독립성이 향상되지만, 모든 상황에 완벽한 솔루션은 아니다.
REST 원칙을 이해하고, 적절한 상황에 적용하며, 필요할 때 다른 API 스타일(GraphQL, gRPC 등)과 함께 사용하는 것이 중요하다. 이러한 지식을 바탕으로 효율적이고 확장 가능한 웹 서비스를 설계하고 구현할 수 있을 것이다.
REST의 6가지 제약 조건
REST API를 진정한 의미에서 “RESTful"하게 만들기 위해서는 다음 6가지 제약 조건을 준수해야 한다:
클라이언트-서버 아키텍처(Client-Server Architecture)
- 사용자 인터페이스와 데이터 저장을 분리해야 한다.
- 이를 통해 클라이언트와 서버는 독립적으로 진화할 수 있다.
무상태성(Statelessness)
- 각 요청에는 그 요청을 이해하는 데 필요한 모든 정보가 포함되어야 한다.
- 서버는 클라이언트의 세션 상태를 저장하지 않는다.
- 모든 상태 정보는 클라이언트가 관리한다.
캐시 가능성(Cacheability)
- 응답은 캐싱 가능 여부를 명시해야 한다.
- 효율적인 캐싱은 일부 클라이언트-서버 상호작용을 제거하여 성능을 향상시킨다.
계층화 시스템(Layered System)
- 클라이언트는 일반적으로 서버에 직접 연결되는지 중간 서버에 연결되는지 알 수 없다.
- 중간 계층(로드 밸런서, 프록시, 게이트웨이 등)은 확장성을 향상시키고 보안 정책을 적용할 수 있다.
통일된 인터페이스(Uniform Interface)
- REST API의 가장 중요한 특징으로, 다음 네 가지 원칙으로 구성된다:
- 자원 식별(Resource Identification): URI를 통해 자원을 고유하게 식별한다.
- 표현을 통한 자원 조작(Manipulation of Resources Through Representations): 클라이언트가 자원의 표현을 가지고 있다면, 서버상의 해당 자원을 수정할 권한이 있어야 한다.
- 자기 서술적 메시지(Self-descriptive Messages): 각 메시지는 자신을 어떻게 처리해야 하는지에 대한 정보를 포함해야 한다.
- 애플리케이션 상태 엔진으로서의 하이퍼미디어(HATEOAS): 클라이언트는 초기 URI 외에는 하드코딩된 URI를 사용하지 않고, 서버가 제공하는 링크를 통해 애플리케이션 내에서 상태 전이를 할 수 있어야 한다.
- REST API의 가장 중요한 특징으로, 다음 네 가지 원칙으로 구성된다:
코드 온 디맨드(Code on Demand, 선택적)
- 서버가 클라이언트에 실행 가능한 코드를 전송하여 기능을 확장할 수 있다.
- 이는 유일한 선택적 제약 조건이다(예: JavaScript).
자원(Resources)과 URI 설계
RESTful API에서 가장 기본적인 개념은 “자원(Resource)“이다.
자원은 명사로 표현되며, URI를 통해 식별된다.
자원의 특성
- 자원은 개념적 대상(예: 사용자, 상품, 주문)이다.
- 자원은 단수 또는 복수 개념으로 존재할 수 있다.
- 자원은 다른 자원과 관계를 맺을 수 있다.
URI 설계 원칙
- 자원을 명사로 표현:
/users
,/products
,/orders
- 계층 관계 표현:
/users/123/orders
- 복수형 사용:
/users
(단수형인/user
대신) - 소문자 사용:
/users
(대문자인/Users
대신) - 언더스코어(_) 대신 하이픈(-) 사용:
/order-items
(언더스코어인/order_items
대신) - 파일 확장자 사용 자제:
/users
(확장자 있는/users.json
대신) - 행위(동사)는 URI에 포함시키지 않음:
/users
(동사 포함한/getUsers
대신)
HTTP 메서드와 CRUD 연산
RESTful API는 HTTP 메서드를 사용하여 자원에 대한 CRUD(Create, Read, Update, Delete) 연산을 수행한다.
주요 HTTP 메서드
- GET: 자원을 조회한다 (Read).
- 예:
GET /users/123
- ID가 123인 사용자 정보 조회 - 데이터를 변경하지 않는 안전한(safe) 요청이어야 한다.
- 여러 번 호출해도 동일한 결과를 반환하는 멱등성(idempotent)을 가진다.
- 예:
- POST: 새 자원을 생성한다 (Create).
- 예:
POST /users
- 새 사용자 생성 - 요청 본문(body)에 생성할 자원의 내용을 포함한다.
- 멱등성을 가지지 않는다(여러 번 호출하면 여러 자원이 생성됨).
- 예:
- PUT: 자원을 수정하거나 없으면 생성한다 (Update/Create).
- 예:
PUT /users/123
- ID가 123인 사용자 정보 업데이트 - 멱등성을 가집니다(같은 요청을 여러 번 해도 결과는 동일).
- 요청에 자원의 전체 표현이 포함되어야 한다.
- 예:
- PATCH: 자원의 일부를 수정한다 (Partial Update).
- 예:
PATCH /users/123
- ID가 123인 사용자의 일부 정보만 업데이트 - 요청에는 변경할 필드만 포함한다.
- 일반적으로 멱등성을 가진다(구현에 따라 다를 수 있음).
- 예:
- DELETE: 자원을 삭제한다 (Delete).
- 예:
DELETE /users/123
- ID가 123인 사용자 삭제 - 멱등성을 가집니다(여러 번 호출해도 결과는 동일).
- 예:
기타 HTTP 메서드
- HEAD: GET과 동일하지만 응답 본문 없이 헤더만 반환한다.
- OPTIONS: 자원에 대해 사용 가능한 HTTP 메서드를 반환한다.
HTTP 상태 코드
RESTful API는 표준 HTTP 상태 코드를 사용하여 요청의 결과를 나타낸다.
상태 코드는 클라이언트가 요청의 성공 여부와 다음 조치를 이해하는 데 중요하다.
주요 HTTP 상태 코드 범주
- 1xx (정보): 요청이 수신되어 처리 중이다.
- 2xx (성공): 요청이 성공적으로 처리되었다.
- 3xx (리다이렉션): 요청 완료를 위해 추가 조치가 필요하다.
- 4xx (클라이언트 오류): 요청에 오류가 있어 처리할 수 없다.
- 5xx (서버 오류): 서버가 유효한 요청을 처리하지 못했다.
자주 사용되는 상태 코드
- 200 OK: 요청이 성공했다.
- 201 Created: 자원이 성공적으로 생성되었다.
- 204 No Content: 요청은 성공했지만 반환할 콘텐츠가 없다.
- 400 Bad Request: 요청 구문이 잘못되었다.
- 401 Unauthorized: 인증이 필요하다.
- 403 Forbidden: 권한이 없다.
- 404 Not Found: 요청한 자원을 찾을 수 없다.
- 405 Method Not Allowed: 해당 자원에 대해 요청한 메서드가 허용되지 않는다.
- 409 Conflict: 요청이 현재 서버 상태와 충돌한다.
- 500 Internal Server Error: 서버에 오류가 발생했다.
미디어 타입과 콘텐츠 협상
RESTful API에서는 다양한 형식으로 자원을 표현할 수 있으며, 클라이언트와 서버 간의 ‘콘텐츠 협상(Content Negotiation)‘을 통해 가장 적합한 표현을 선택한다.
주요 미디어 타입
- application/json: JSON 형식 (현대 웹 API에서 가장 흔히 사용)
- application/xml: XML 형식
- application/hal+json: Hypertext Application Language, 하이퍼미디어 제약조건 지원
- application/vnd.api+json: JSON API 규격
- text/html: HTML 형식
콘텐츠 협상 방법
- 클라이언트가 요청 헤더로 선호하는 형식 지정:
Accept: application/json
Accept-Language: ko-KR
- 서버가 응답 헤더로 제공하는 형식 명시:
Content-Type: application/json; charset=utf-8
하이퍼미디어와 HATEOAS
HATEOAS(Hypermedia as the Engine of Application State)는 REST의 성숙도 모델에서 가장 높은 수준으로, 클라이언트가 API를 탐색할 수 있는 링크를 제공한다.
HATEOAS의 핵심 개념
- 클라이언트는 API 엔드포인트의 URI를 하드코딩하지 않는다.
- 서버는 응답에 관련 자원으로의 링크를 포함한다.
- 클라이언트는 이 링크를 통해 API를 동적으로 탐색한다.
HATEOAS 예시 (JSON 형식)
보안
RESTful API의 보안은 여러 계층에서 구현될 수 있다.
인증(Authentication) 방법
- API 키: 요청에 API 키를 포함시켜 클라이언트를 식별한다.
- OAuth 2.0: 사용자 자격 증명 없이 API에 안전하게 액세스할 수 있는 토큰 기반 인증이다.
- JWT(JSON Web Tokens): 클레임을 안전하게 전송할 수 있는 컴팩트한 토큰 형식이다.
- 기본 인증(Basic Auth): 사용자 이름과 비밀번호를 Base64로 인코딩하여 전송한다.
권한 부여(Authorization)
- 인증된 사용자가 특정 자원에 접근하거나 특정 작업을 수행할 수 있는 권한을 확인한다.
- 역할 기반(Role-based)이나 속성 기반(Attribute-based) 접근 제어를 구현할 수 있다.
기타 보안 고려사항
- HTTPS 사용: 모든 API 통신은 TLS/SSL을 통해 암호화되어야 한다.
- 요청 제한(Rate Limiting): 과도한 요청을 방지하기 위해 클라이언트당 API 호출 횟수를 제한한다.
- CORS(Cross-Origin Resource Sharing): 브라우저 기반 클라이언트를 위한 보안 정책이다.
- 입력 검증: 모든 클라이언트 입력은 서버 측에서 검증되어야 한다.
API 버전 관리
API가 진화함에 따라 기존 클라이언트의 호환성을 유지하면서 새로운 기능을 추가할 수 있는 버전 관리가 중요하다.
버전 관리 접근법
- URI 경로:
/api/v1/users
,/api/v2/users
- 쿼리 파라미터:
/api/users?version=1
- HTTP 헤더:
Accept: application/vnd.company.api+json;version=1
- 콘텐츠 협상:
Accept: application/vnd.company.v1+json
각 방식에는 장단점이 있으므로, 프로젝트 요구사항에 가장 적합한 방식을 선택해야 한다.
문서화
좋은 API 문서는 개발자가 API를 효과적으로 사용하는 데 필수적이다.
API 문서화 도구
- Swagger/OpenAPI: API 설계, 구축, 문서화, 소비를 돕는 규격과 도구 세트.
- RAML(RESTful API Modeling Language): API 설계를 위한 YAML 기반의 언어.
- API Blueprint: API 문서화를 위한 마크다운 기반 언어.
- Postman: API 테스트 및 문서화를 위한 강력한 도구.
문서화 모범 사례
- 각 엔드포인트의 목적을 명확히 설명한다.
- 필요한 파라미터와 응답 형식을 자세히 기술한다.
- 예제 요청과 응답을 포함한다.
- 오류 조건과 상태 코드를 문서화한다.
- 인증 요구사항을 명확히 설명한다.
REST 성숙도 모델(Richardson Maturity Model)
레오나르드 리처드슨(Leonard Richardson)이 제안한 REST API의 성숙도 모델은 4단계로 구성된다:
레벨 0: HTTP를 전송 메커니즘으로만 사용
- 단일 URI와 단일 HTTP 메서드(보통 POST)만 사용한다.
- SOAP이나 XML-RPC와 유사하다.
레벨 1: 자원(Resources)
- 다양한 URI를 통해 개별 자원을 식별한다.
- 여전히 단일 HTTP 메서드에 의존한다.
레벨 2: HTTP 동사
- 다양한 HTTP 메서드(GET, POST, PUT, DELETE 등)를 사용하여 자원을 조작한다.
- HTTP 상태 코드를 적절히 사용한다.
레벨 3: 하이퍼미디어 제어(HATEOAS)
- 응답에 관련 자원으로의 링크를 포함한다.
- 클라이언트가 API를 동적으로 탐색할 수 있다.
많은 현대 API는 레벨 2에 해당하며, 레벨 3(HATEOAS)는 완전한 RESTful API를 위한 요구사항이지만 실제로 구현하기 어려운 경우가 많다.
REST API 설계 모범 사례
자원 식별과 URI 디자인
- 명사 기반 자원 표현을 사용한다.
- 일관된 복수형 명명 규칙을 유지한다.
- 계층적 관계를 URI에 반영한다.
메서드 사용
- HTTP 메서드의 의미에 맞게 API를 설계한다.
- 멱등성과 안전성을 고려한다.
- 특수 작업은 하위 자원으로 모델링한다(예:
/users/123/activate
).
상태 코드
- 표준 HTTP 상태 코드를 사용한다.
- 오류 응답에 의미 있는 메시지를 포함한다.
페이지네이션, 필터링, 정렬
- 컬렉션 자원에 페이지네이션을 구현한다(예:
?page=2&size=10
). - 필터링을 위한 쿼리 파라미터를 제공한다(예:
?status=active
). - 정렬을 위한 파라미터를 지원한다(예:
?sort=name,asc
).
- 컬렉션 자원에 페이지네이션을 구현한다(예:
응답 형식
- 일관된 응답 구조를 유지한다.
- 필요한 메타데이터를 포함한다.
- 오류 응답을 표준화한다.
성능 최적화
- 적절한 캐싱 헤더를 사용한다.
- 필요한 데이터만 반환하도록 최적화한다.
- 압축(gzip, deflate)을 사용한다.
REST API와 다른 API 스타일 비교
REST vs. SOAP
- 형식: REST는 주로 JSON, SOAP는 XML만 사용한다.
- 프로토콜: REST는 HTTP에 의존, SOAP는 여러 프로토콜(HTTP, SMTP 등)을 지원한다.
- 통신: REST는 주로 비동기적, SOAP는 동기적이다.
- 캐싱: REST는 쉽게 캐싱 가능, SOAP는 제한적이다.
- 보안: SOAP는 WS-Security와 같은 내장 표준이 있고, REST는 더 다양한 방식을 사용한다.
REST vs. GraphQL
- 엔드포인트: REST는 여러 엔드포인트, GraphQL은 주로 단일 엔드포인트를 사용한다.
- 데이터 가져오기: REST는 서버가 정의한 응답 구조, GraphQL은 클라이언트가 필요한 데이터를 정확히 지정할 수 있다.
- 버전 관리: REST는 명시적인 버전 관리가 필요, GraphQL은 필드 수준 버전 관리가 가능하다.
- 오버페칭/언더페칭: REST는 이런 문제가 발생할 수 있으나, GraphQL은 이를 해결하도록 설계되었다.
REST vs. gRPC
- 프로토콜: REST는 HTTP/1.1, gRPC는 HTTP/2를 사용한다.
- 데이터 형식: REST는 주로 JSON, gRPC는 Protocol Buffers를 사용한다.
- 코드 생성: gRPC는 강력한 코드 생성 기능을 제공한다.
- 스트리밍: gRPC는 양방향 스트리밍에 뛰어나다.
- 성능: gRPC가 일반적으로 더 효율적이고 빠르다.
RESTful API의 한계
REST가 많은 장점을 제공하지만, 몇 가지 한계와 도전 과제도 있다:
오버페칭과 언더페칭
- 클라이언트가 필요한 데이터보다 많거나 적은 데이터를 받을 수 있다.
- 여러 관련 자원을 조회하려면 여러 API 호출이 필요할 수 있다.
문서화 표준 부족
- REST 자체는 API 문서화를 위한 표준 방식을 정의하지 않는다.
- OpenAPI와 같은 도구가 이 문제를 해결하기 위해 등장했다.
복잡한 트랜잭션
- 여러 자원에 걸친 트랜잭션 처리는 REST에서 자연스럽게 지원되지 않는다.
HATEOAS 구현의 어려움
- 완전한 HATEOAS 구현은 복잡하고 많은 오버헤드를 발생시킬 수 있다.
용어 정리
용어 | 설명 |
---|---|
참고 및 출처
RESTful API: Principles, Design, and Best Practices | Leapcell