REST API
REST API(Representational State Transfer Application Programming Interface)는 네트워크 상에서 서로 다른 컴퓨터 시스템 간의 통신을 가능하게 하는 규칙 세트로, 주로 HTTP를 통해 작동한다. REST API는 웹 애플리케이션에서 서버와 클라이언트 간의 상호작용을 쉽게 하기 위한 방법으로 사용된다. REST는 특히 확장성과 단순함을 제공하여 현대의 웹 애플리케이션에서 매우 중요한 역할을 한다.
1. REST의 개념과 원리
REST는 Representational State Transfer의 약자로, 자원(Resource)을 HTTP URI로 식별하고, 해당 자원에 대한 상태 정보를 HTTP 메서드로 처리하는 구조이다. REST는 주로 웹 애플리케이션에서 서버-클라이언트 간 상호작용을 단순화하고, 확장성을 높이기 위해 사용된다.
1.1. 자원의 표현(Representation)
REST에서 자원은 데이터베이스의 개체나 객체와 유사한 개념이다. 예를 들어, 사용자, 게시글, 상품 등이 자원이 될 수 있다. 각 자원은 고유한 URI(Uniform Resource Identifier)로 식별되며, 이 자원을 표현하는 방식은 여러 가지일 수 있다. JSON, XML, HTML 등이 그 예이다.
1.2. 상태 전이(State Transfer)
자원에 대한 작업(읽기, 쓰기, 수정, 삭제)이 이루어질 때 클라이언트와 서버 간의 상태 전이가 발생한다. 이 상태 전이는 HTTP 메서드를 사용하여 수행되며, 서버는 자원의 상태를 변경하거나 새로운 자원을 생성하는 역할을 한다.
2. HTTP 메서드의 역할
REST API는 다음과 같은 주요 HTTP 메서드를 사용하여 자원을 다룬다.
2.1. GET
GET 메서드는 서버로부터 특정 자원에 대한 정보를 요청하는 데 사용된다. 데이터를 조회할 때 사용되며, 서버의 상태를 변경하지 않는다. GET 요청은 무상태(stateless) 특성을 가지고 있으며, 반복적으로 호출해도 서버 상태에 영향을 주지 않는다.
- 예시: 특정 사용자 정보 조회
- 응답:
- { "id": 123, "name": "Jane Doe", "email": "jane@example.com" }
- GET /users/123 HTTP/1.1 Host: api.example.com
2.2. POST
POST 메서드는 서버에 새로운 자원을 생성할 때 사용된다. 클라이언트에서 서버로 데이터를 전송하여 자원 생성 요청을 한다. POST 요청이 성공적으로 처리되면, 서버는 새로 생성된 자원의 URI를 반환하거나 새로 생성된 자원의 정보를 반환할 수 있다.
- 예시: 새로운 사용자 생성
- 응답:
- { "id": 124, "name": "John Doe", "email": "john@example.com" }
- POST /users HTTP/1.1 Host: api.example.com Content-Type: application/json { "name": "John Doe", "email": "john@example.com" }
2.3. PUT
PUT 메서드는 서버의 기존 자원을 업데이트(수정)할 때 사용된다. 주로 특정 자원의 전체 정보를 대체하는 방식으로 동작하며, 지정된 자원이 없으면 새로 생성할 수도 다.
- 예시: 사용자 정보 수정
- PUT /users/123 HTTP/1.1 Host: api.example.com Content-Type: application/json { "name": "Jane Smith", "email": "jane.smith@example.com" }
2.4. PATCH
PATCH 메서드는 PUT과 유사하지만, 자원의 일부분만 수정할 때 사용된다. 즉, 전체 자원을 대체하지 않고 일부 속성만 변경할 수 있다.
- 예시: 사용자의 이메일만 변경
- PATCH /users/123 HTTP/1.1 Host: api.example.com Content-Type: application/json { "email": "new.email@example.com" }
2.5. DELETE
DELETE 메서드는 특정 자원을 삭제하는 데 사용된다. 자원이 삭제되면, 서버는 해당 자원에 대해 더 이상 접근할 수 없도록 해야 한다.
- 예시: 특정 사용자 삭제
- DELETE /users/123 HTTP/1.1 Host: api.example.com
2.6. GET과 POST의 차이
GET:
- 목적: 서버에서 데이터를 가져오는 데 사용된다.
- 특징:
- 데이터를 서버에 보내지 않고 서버에서 자원을 요청하는 메서드이다.
- 주로 URL에 파라미터를 포함하여 데이터를 요청한다.
- 안전한 메서드로 간주된다: 서버의 상태를 변경하지 않는다.
- 캐싱이 가능하다. 브라우저나 프록시가 GET 요청의 응답을 캐싱하여 성능을 향상시킬 수 있다.
- Idempotent(멱등성) 특성을 가진다. 동일한 요청을 여러 번 보내더라도 서버의 상태는 변하지 않는다.
POST:
- 목적: 서버에 데이터를 보내서 새로운 자원을 생성하거나 작업을 처리할 때 사용된다.
- 특징:
- 서버의 상태를 변경하는 데이터 전송에 사용된다.
- URL이 아닌 요청 본문(body)에 데이터를 포함시켜 전송한다.
- 서버에 새로운 자원을 생성하거나 서버에서 처리할 작업을 요청할 때 주로 사용된다.
- 캐싱되지 않는다. 항상 서버에 새로운 요청으로 처리된다.
- **Idempotent(멱등)**하지 않는다. 동일한 요청을 여러 번 보내면 중복된 자원 생성이나 작업이 발생할 수 있다.
2.7. PUT과 PATCH의 차이
PUT:
- 목적: 서버의 기존 자원을 완전히 수정하거나 교체할 때 사용된다.
- 특징:
- 서버에 지정된 자원이 있을 경우, 해당 자원을 완전히 대체한다.
- 자원이 없을 경우, 서버가 새로운 자원을 생성할 수도 있다.
- Idempotent하다. 동일한 요청을 여러 번 보내더라도 결과는 항상 같다. 즉, 자원의 상태가 계속 동일하게 유지된다.
- PUT은 클라이언트가 자원의 전체 상태를 서버로 전송해야 한다. 이로 인해 자원의 모든 속성을 포함해야 한다.
- 예시: 사용자 정보 전체 수정이 요청을 통해 id=1인 사용자의 모든 정보가 새롭게 업데이트 된다. 기존 정보는 대체된다.
- PUT /users/1 HTTP/1.1 Host: example.com Content-Type: application/json { "name": "John Smith", "email": "john.smith@example.com" }
PATCH:
- 목적: 서버의 기존 자원의 일부분을 수정할 때 사용된다.
- 특징:
- 자원의 일부 속성만 수정한다. 전체 자원이 아닌, 일부 속성만 전달하여 변경할 수 있다.
- Idempotent하지 않는다. 동일한 요청을 여러 번 보냈을 때 결과가 달라질 수 있다. 그러나 일반적으로 많은 구현에서는 PATCH도 Idempotent하게 동작한다.
- 빠르고 효율적이다. 변경할 부분만 서버로 전송하면 되기 때문에, 대규모 자원을 수정하는 경우 효율적이다.
- 예시: 사용자 이메일만 수정이 요청을 통해 사용자의 이메일 주소만 수정된다. 나머지 정보는 변경되지 않는다.
- PATCH /users/1 HTTP/1.1 Host: example.com Content-Type: application/json { "email": "new.email@example.com" }
- GET vs POST:
- GET: 데이터를 가져오기 위한 요청. 서버의 상태를 변경하지 않음.
- POST: 데이터를 서버로 보내기 위한 요청. 서버에 새로운 자원을 생성하거나 작업을 처리함.
- PUT vs PATCH:
- PUT: 자원 전체를 수정. 자원의 모든 속성을 대체하며, 자원이 없으면 새로 생성 가능.
- PATCH: 자원의 일부분만 수정. 변경할 부분만 서버로 전송하여 수정함.
3. 무상태성 (Statelessness)
REST의 중요한 특징 중 하나는 무상태성(stateless)이다. 서버는 클라이언트의 상태 정보를 유지하지 않으며, 각 요청은 독립적으로 처리된다. 이는 클라이언트가 요청 시 필요한 모든 정보를 포함해야 함을 의미한다.
- 예를 들어, 사용자가 로그인한 후 각 요청마다 인증 정보를 전달해야 한다. 일반적으로 API 키나 JWT(JSON Web Token) 등의 인증 토큰을 헤더에 포함시켜 요청한다.
GET /users/123 HTTP/1.1
Host: api.example.com
Authorization: Bearer <token>
4. HTTP 상태 코드 (HTTP Status Codes)
REST API는 클라이언트 요청에 대한 응답으로 다양한 HTTP 상태 코드를 반환한다. 각 상태 코드는 클라이언트가 요청이 성공적으로 처리되었는지, 문제가 있었는지 확인하는 데 사용된다.
- 200 OK: 요청이 성공적으로 처리되었다.
- 201 Created: 새로운 자원이 성공적으로 생성되었다.
- 400 Bad Request: 잘못된 요청이다. 클라이언트의 요청이 잘못된 형식이거나 유효하지 않은 데이터를 포함한다.
- 401 Unauthorized: 인증되지 않은 사용자로부터의 요청이다.
- 403 Forbidden: 인증은 되었지만 해당 자원에 접근할 권한이 없다.
- 404 Not Found: 요청한 자원을 찾을 수 없다.
- 500 Internal Server Error: 서버에서 요청을 처리하는 동안 문제가 발생했다.
5. RESTful 설계 원칙
REST API는 RESTful해야 한다는 원칙을 따른다. RESTful 설계는 다음과 같은 중요한 특성을 가진다.
5.1. 일관된 인터페이스(Uniform Interface)
클라이언트와 서버 간의 통신은 일관된 방식으로 이루어져야 한다. 클라이언트는 서버의 내부 동작을 알 필요 없이, URI 및 HTTP 메서드를 통해 자원을 요청한다.
5.2. 클라이언트-서버 구조(Client-Server Architecture)
클라이언트는 사용자 인터페이스와 관련된 로직을 처리하고, 서버는 데이터 처리 및 저장을 담당한다. 이 구조는 시스템의 유연성과 확장성을 증가시킨다.
5.3. 캐싱 가능성(Cacheability)
REST는 클라이언트가 서버로부터 받은 응답을 캐싱할 수 있어야 한다. 이를 통해 불필요한 네트워크 요청을 줄이고, 성능을 향상시킬 수 있다.
5.4. 계층화된 시스템(Layered System)
REST 아키텍처는 계층적으로 설계될 수 있다. 클라이언트와 서버 사이에 프록시, 게이트웨이 또는 로드 밸런서와 같은 계층을 추가하여 시스템의 성능 및 보안을 개선할 수 있다.
6. HATEOAS (Hypermedia as the Engine of Application State)
RESTful 시스템에서 HATEOAS는 클라이언트가 현재의 자원에 대한 상태와 함께 해당 자원과 관련된 링크 정보를 제공받을 수 있음을 의미한다. 즉, 클라이언트는 서버로부터 받은 응답을 통해 더 많은 관련 작업을 탐색할 수 있다.
{
"id": 123,
"name": "Jane Doe",
"email": "jane@example.com",
"_links": {
"self": { "href": "/users/123" },
"friends": { "href": "/users/123/friends" },
"posts": { "href": "/users/123/posts" }
}
}
이 예시에서는 클라이언트가 "friends"와 "posts" 링크를 통해 사용자의 친구 목록이나 게시물을 쉽게 탐색할 수 있다.
7. REST API 보안
REST API는 클라이언트와 서버 간의 중요한 데이터를 주고받기 때문에 보안이 매우 중요하다. 다음은 REST API 보안을 위한 일반적인 방법들이다.
- SSL/TLS: 모든 요청과 응답을 암호화하여 데이터 도난이나 중간자 공격을 방지한다.
- API 키: 클라이언트가 인증된 요청을 보내도록 API 키를 사용한다.
- OAuth: OAuth 2.0은 제3자 인증을 허용하는 표준 프로토콜로, 주로 소셜 네트워크 API에서 사용된다.
- JWT: JWT(JSON Web Token)를 사용하여 클라이언트를 인증하고 권한을 부여한다.
REST API는 현대 웹 개발에서 필수적인 통신 규칙 세트로, 웹 애플리케이션의 서버-클라이언트 간 상호작용을 간편하게 만든다. 특히 무상태성, HTTP 메서드, 상태 코드 및 보안 기능을 고려하여 설계된 RESTful API는 확장 가능하고 유지보수하기 쉬운 시스템을 구축하는 데 매우 유용하다.