REST API 개요
REST(REpresentational State Transfer)는 웹의 장점을 최대한 활용할 수 있는 아키텍처로서 2000년에 등장했다.
HTTP/1.0과 1.1의 스펙 작성에 참여했고 아파치 HTTP 서버 프로젝트의 공동 설립자인 로이 필딩이 자신의 박사학위 논문에서 처음 소개했는데, 이는 당시 웹이 HTTP의 본래 장점을 제대로 활용하지 못하고 있는 상황을 개선하기 위해서였다. 로이 필딩은 HTTP 프로토콜의 의도에 맞게 설계하도록 유도하기 위해 REST를 제안했다.
REST의 정의는 HTTP를 기반으로 클라이언트가 서버의 리소스에 접근하는 방식을 규정한 아키텍처다. REST의 기본 원칙을 성실히 지킨 서비스 디자인을 "RESTful"이라고 표현하는데, 이는 해당 서비스가 REST의 설계 규칙을 잘 지켰다는 것을 의미한다. REST API는 이러한 REST를 기반으로 서비스 API를 구현한 것을 말한다.
REST API의 큰 특징 중 하나는 self-descriptiveness(자체 표현 구조, 셀프 디스크립티브니스)를 갖추고 있다는 점이다. 이는 REST API만으로도 HTTP 요청의 내용을 이해할 수 있다는 것을 의미하는데, 이를 통해 클라이언트와 서버 간의 통신이 더욱 명확해지고 직관적으로 이루어질 수 있다.
REST API 구성
REST API는 자원(resource), 행위(verb), 표현(representations)이라는 3가지 핵심 요소로 구성된다. 각각의 요소는 서로 다른 역할을 하며, 이들이 조화롭게 결합하여 완전한 REST API를 구성한다.
자원(resource)
자원은 REST 아키텍처의 핵심이 되는 개념이다. 서버에 존재하는 모든 데이터나 자원은 고유한 URI(Uniform Resource Identifier)를 통해 식별된다. 이때 URI는 해당 자원의 엔드포인트 역할을 하며, 클라이언트는 이 URI를 통해 원하는 자원에 접근할 수 있다. 예를 들어 사용자 정보를 다루는 API에서 '/users'라는 URI는 사용자라는 자원을 나타내는 것이다.
행위(verb)
행위는 특정 자원에 대해 클라이언트가 수행하고자 하는 동작을 의미한다. 이는 HTTP 요청 메서드를 통해 표현되는데, 각각의 메서드는 자원에 대한 특정한 동작을 나타낸다. HTTP 프로토콜은 GET, POST, PUT, PATCH, DELETE 등 다양한 메서드를 제공하며, 각 메서드는 자원에 대한 서로 다른 동작을 수행한다. 이러한 행위는 URI에 직접적으로 표현되지 않고 HTTP 메서드를 통해 표현되어야 한다.
표현(representations)
표현은 특정 시점에 자원의 상태를 반영하는 정보다. 이는 주로 페이로드를 통해 전달되는데, 페이로드란 전송의 근본적인 목적이 되는 데이터를 의미한다. 여기에는 실제 전송하고자 하는 데이터뿐만 아니라, 해당 데이터를 설명하는 메타데이터와 데이터의 무결성을 검증하기 위한 정보 등도 포함될 수 있다. 페이로드는 주로 JSON이나 XML 같은 형식으로 구조화되어 전송된다.
REST API 설계 원칙
REST API를 설계할 때 가장 중요하게 고려해야 할 핵심 원칙이 두 가지 있다. 하나는 URI가 리소스를 잘 표현해야 한다는 것이고, 다른 하나는 리소스에 대한 행위는 반드시 HTTP 요청 메서드로 표현해야 한다는 것이다. 이 두 가지는 RESTful API를 설계하는 데 있어 가장 기본이 되는 중심 규칙이다.
URI는 리소스를 표현해야 한다
URI는 리소스를 명확하게 표현하는 데 중점을 두어야 한다. 여기서 중요한 점은 리소스를 식별할 수 있는 이름을 지정할 때 동사가 아닌 명사를 사용해야 한다는 것이다. URI에는 get, show, delete와 같은 행위에 대한 표현이 들어가서는 안 된다. 이는 URI가 리소스의 위치나 식별자 역할을 하는 것이지, 해당 리소스에 대한 행위를 나타내는 것이 아니기 때문이다.
GET /getTodos/1 // 행위(get)를 포함
GET /todos/show/1 // 행위(show)를 포함
GET /todos/delete/1 // 행위(delete)를 포함
위는 잘못된 URI 설계의 예시이다.
GET /todos/1 // 리소스만을 식별
PUT /todos/1 // 리소스만을 식별
DELETE /todos/1 // 리소스만을 식별
위는 올바른 URI 설계의 예시이다.
리소스에 대한 행위는 HTTP 요청 메서드로 표현한다
HTTP 요청 메서드는 클라이언트가 서버에게 요청의 종류와 목적(리소스에 대한 행위)을 알리는 핵심적인 방법이다. REST API에서는 주로 다섯 가지의 요청 메서드를 사용하여 CRUD(Create, Read, Update, Delete)를 구현한다. 각 메서드의 특징과 용도는 다음과 같다.
- GET (Read)
- 리소스를 조회하는 메서드다.
- 서버에서 데이터를 가져올 때만 사용한다.
- 요청 시 body에 데이터를 담아 보내지 않는다.
- 성공적인 요청은 200(OK) 상태 코드를 반환한다.
- POST (Create)
- 새로운 리소스를 생성하는 메서드다.
- 요청 시 body에 생성할 리소스의 데이터를 담아 보낸다.
- 성공적인 생성은 201(Created) 상태 코드를 반환한다.
- PUT (Update)
- 리소스를 완전히 대체하는 메서드다.
- 요청 시 body에 교체할 리소스의 전체 데이터를 담아 보낸다.
- 해당 리소스가 없으면 새로 생성할 수도 있다.
- PATCH (Update)
- 리소스를 부분적으로 수정하는 메서드다.
- 요청 시 body에 수정할 데이터만 담아 보낸다.
- PUT과 달리 일부 데이터만 변경할 때 사용한다.
- DELETE (Delete)
- 리소스를 삭제하는 메서드다.
- 일반적으로 body를 담아 보내지 않는다.
- 성공적인 삭제는 204(No Content) 상태 코드를 반환한다.
이러한 HTTP 메서드들은 각각의 용도가 명확하게 구분되어 있어, API의 의도를 명확하게 표현할 수 있다. 또한 이들은 멱등성(idempotency)이라는 특성을 가지고 있는데, GET, PUT, DELETE는 멱등성을 가지며 POST는 멱등성을 가지지 않는다. 여기서 멱등성이란 동일한 요청을 여러 번 보내도 서버의 상태가 동일하게 유지되는 성질을 말한다.
멱등성 (Idempotency)
멱등성이란 여러 번 수행해도 결과가 같은 성질을 말한다. 수학적으로는 연산을 여러 번 적용하더라도 결과가 달라지지 않는 성질을 의미한다. HTTP에서는 동일한 요청을 한 번 보내는 것과 여러 번 연속으로 보내는 것이 같은 효과를 지니고, 서버의 상태도 동일하게 남는 것을 의미한다.
쉬운 예시로 이해하기
- GET 요청 (멱등)
- 도서관에서 책의 정보를 조회하는 것과 같다.
- 같은 책의 정보를 한 번 조회하나 열 번 조회하나 정보는 변함없이 동일하다.
- DELETE 요청 (멱등)
- 이미 지워진 파일을 다시 지우려고 시도하는 것과 같다.
- 첫 번째 삭제 시도에서 파일이 삭제되고, 그 이후의 삭제 시도는 이미 없는 파일을 대상으로 하므로 서버의 상태는 변함이 없다.
- PUT 요청 (멱등)
- 화이트보드의 내용을 새로운 내용으로 덮어쓰는 것과 같다.
- 같은 내용으로 한 번 덮어쓰나 여러 번 덮어쓰나 최종 결과는 동일하다.
- POST 요청 (비멱등)
- 은행 계좌에 돈을 입금하는 것과 같다.
- 동일한 입금 요청을 여러 번 보내면 그만큼 잔액이 증가하므로 결과가 달라진다.
HTTP 메서드별 멱등성
HTTP 메서드 | 멱등성 | 설명 |
GET | O | 리소스 조회만 수행하므로 몇 번을 호출하더라도 같은 결과 반환 |
HEAD | O | GET과 동일하게 리소스 조회만 수행 |
PUT | O | 전체 리소스를 항상 동일한 데이터로 교체 |
DELETE | O | 이미 삭제된 리소스를 다시 삭제하더라도 서버는 동일한 상태 유지 |
POST | X | 매 요청마다 새로운 리소스가 생성되거나 상태가 변경됨 |
PATCH | △ | 구현 방식에 따라 멱등할 수도, 멱등하지 않을 수도 있음 |
멱등성은 실제 애플리케이션 개발에서 중요한 의미를 가진다. 특히 네트워크 문제로 인한 재시도 상황에서, 멱등성이 보장되는 메서드는 안전하게 재시도를 수행할 수 있다. 반면 POST와 같은 비멱등 메서드는 재시도 시 의도치 않은 결과가 발생할 수 있으므로 주의가 필요하다.
JSON Server를 이용한 REST API 실습
HTTP 요청을 전송하고 응답을 받기 위해서는 서버가 필요하다. 이를 위해 JSON Server를 사용해 가상의 REST API 서버를 구축하여 실습을 진행할 수 있다. JSON Server는 json 파일을 사용하여 간단한 DB와 REST API 서버를 구축할 수 있게 해주는 유용한 도구다.
JSON Server 설치
먼저 npm(Node Package Manager)을 사용하여 JSON Server를 설치한다. 실습을 위한 프로젝트 디렉토리를 생성하고 그 안에서 다음 명령어를 실행한다.
$ mkdir json-server-exam && cd json-server-exam
$ npm init -y
$ npm install json-server --save-dev
여기서 --save-dev 옵션은 이 패키지가 개발 환경에서만 필요하다는 것을 명시하는 것이다.
db.json 파일 생성
프로젝트 루트 폴더에 db.json 파일을 생성하고 다음과 같이 기본 데이터를 추가한다.
{
"todos": [
{
"id": 1,
"content": "HTML",
"completed": true
},
{
"id": 2,
"content": "CSS",
"completed": false
},
{
"id": 3,
"content": "Javascript",
"completed": true
}
]
}
이 파일은 실제 데이터베이스 역할을 하며, 여기에 정의된 todos 배열이 우리가 조작할 리소스가 된다.
JSON Server 실행
JSON Server를 더 편리하게 실행하기 위해 package.json 파일의 scripts 부분을 다음과 같이 수정한다.
{
"name": "json-server-exam",
"version": "1.0.0",
"scripts": {
"start": "json-server --watch db.json"
},
"devDependencies": {
"json-server": "^0.16.1"
}
}
이제 npm start 명령어로 서버를 실행할 수 있다. --watch 옵션은 db.json 파일의 변경을 감지하여 자동으로 서버에 반영하게 한다. 기본 포트는 3000번이며, 필요한 경우 --port 옵션으로 변경할 수 있다.
GET 요청
GET 요청은 리소스를 조회하는 데 사용되며, 크게 전체 목록을 조회하는 경우와 특정 리소스를 조회하는 경우로 나눌 수 있다.
먼저 모든 todos를 조회하는 예제를 살펴보자.
<!DOCTYPE html>
<html>
<body>
<pre></pre>
<script>
// XMLHttpRequest 객체 생성
const xhr = new XMLHttpRequest();
// todos 리소스에서 모든 todo를 취득하기 위한 요청 초기화
xhr.open('GET', '/todos');
// HTTP 요청 전송
xhr.send();
// 요청이 완료되면 실행될 이벤트 핸들러
xhr.onload = () => {
// 응답이 성공적으로 완료된 경우 (200 OK)
if (xhr.status === 200) {
document.querySelector('pre').textContent = xhr.response;
} else {
console.error('Error', xhr.status, xhr.statusText);
}
};
</script>
</body>
</html>
특정 id의 todo만 조회하고 싶다면 다음과 같이 구현한다.
// 요청 초기화 부분만 다음과 같이 변경
xhr.open('GET', '/todos/1'); // 1번 id를 가진 todo 조회
POST 요청
POST 요청은 새로운 리소스를 생성할 때 사용한다. 이때 중요한 점은 요청 헤더에 콘텐츠 타입을 지정해야 한다는 것이다.
<!DOCTYPE html>
<html>
<body>
<pre></pre>
<script>
const xhr = new XMLHttpRequest();
// 새로운 todo 생성을 위한 요청 초기화
xhr.open('POST', '/todos');
// 요청 헤더에 JSON 형식임을 명시
xhr.setRequestHeader('content-type', 'application/json');
// 새로운 todo 데이터를 JSON 형식으로 전송
xhr.send(JSON.stringify({
id: 4,
content: "Angular",
completed: false
}));
xhr.onload = () => {
// POST 요청 성공은 200(OK) 또는 201(Created)
if (xhr.status === 200 || xhr.status === 201) {
document.querySelector('pre').textContent = xhr.response;
} else {
console.error('Error', xhr.status, xhr.statusText);
}
};
</script>
</body>
</html>
PUT 요청
PUT은 특정 리소스 전체를 교체할 때 사용한다. 이는 리소스의 모든 필드를 새로운 값으로 덮어쓴다는 의미다.
<!DOCTYPE html>
<html>
<body>
<pre></pre>
<script>
const xhr = new XMLHttpRequest();
// 4번 id를 가진 todo를 교체하기 위한 요청 초기화
xhr.open('PUT', '/todos/4');
xhr.setRequestHeader('content-type', 'application/json');
// 리소스 전체를 교체할 새로운 데이터 전송
xhr.send(JSON.stringify({
id: 4,
content: "React",
completed: true
}));
xhr.onload = () => {
if (xhr.status === 200) {
document.querySelector('pre').textContent = xhr.response;
} else {
console.error('Error', xhr.status, xhr.statusText);
}
};
</script>
</body>
</html>
PATCH 요청
PATCH는 PUT과 달리 리소스의 일부분만 수정할 때 사용한다. 예를 들어, todo 항목에서 completed 상태만 변경하고 싶을 때 PATCH를 사용하면 효율적이다.
<!DOCTYPE html>
<html>
<body>
<pre></pre>
<script>
const xhr = new XMLHttpRequest();
// 4번 id를 가진 todo의 일부 수정을 위한 요청 초기화
xhr.open('PATCH', '/todos/4');
xhr.setRequestHeader('content-type', 'application/json');
// completed 상태만 변경
xhr.send(JSON.stringify({ completed: false }));
xhr.onload = () => {
if (xhr.status === 200) {
document.querySelector('pre').textContent = xhr.response;
} else {
console.error('Error', xhr.status, xhr.statusText);
}
};
</script>
</body>
</html>
이러한 PUT과 PATCH의 주요 차이점은 다음과 같다.
- PUT: 리소스의 모든 필드를 새로운 데이터로 교체한다.
- PATCH: 전달한 필드만 수정하고 나머지는 기존 데이터를 유지한다.
DELETE 요청
DELETE는 특정 리소스를 삭제할 때 사용한다. 다른 요청들과 달리 보통 요청 본문(payload)이 필요하지 않다.
<!DOCTYPE html>
<html>
<body>
<pre></pre>
<script>
const xhr = new XMLHttpRequest();
// 4번 id를 가진 todo 삭제를 위한 요청 초기화
xhr.open('DELETE', '/todos/4');
// DELETE 요청은 보통 페이로드가 필요 없다
xhr.send();
xhr.onload = () => {
// 성공적으로 삭제된 경우
if (xhr.status === 200) {
document.querySelector('pre').textContent = xhr.response;
} else {
console.error('Error', xhr.status, xhr.statusText);
}
};
</script>
</body>
</html>
HTTP 요청 시 주의사항
- 상태 코드 처리
- 200(OK): 대부분의 성공적인 요청에서 반환된다.
- 201(Created): 새로운 리소스가 성공적으로 생성되었을 때 반환된다.
- 404(Not Found): 요청한 리소스가 서버에 없을 때 반환된다.
- 500(Internal Server Error): 서버에서 에러가 발생했을 때 반환된다.
- MIME 타입 지정
- POST, PUT, PATCH와 같이 요청 본문이 있는 경우, 반드시 Content-Type 헤더를 지정해야 한다.
- JSON 데이터를 전송할 때는 'application/json'을 사용한다.
- 에러 처리
- 모든 HTTP 요청에는 적절한 에러 처리가 포함되어야 한다.
- 상태 코드를 확인하여 요청의 성공/실패를 판단한다.
- 실패 시 사용자에게 적절한 피드백을 제공해야 한다.
요약
REST API의 기본 개념과 역사
- REST(Representational State Transfer)는 HTTP의 장점을 최대한 활용할 수 있는 아키텍처로, 2000년 로이 필딩의 박사학위 논문에서 처음 소개되었다.
- HTTP/1.0과 1.1의 스펙 작성에 참여했던 로이 필딩은 당시 웹이 HTTP를 제대로 사용하지 못하는 상황을 보고 HTTP 프로토콜을 올바르게 사용하도록 유도하기 위해 REST를 제안했다.
- REST는 HTTP를 기반으로 클라이언트가 서버의 리소스에 접근하는 방식을 규정한 아키텍처다.
- REST의 기본 원칙을 성실히 지킨 서비스 디자인을 "RESTful"이라고 부르며, REST API는 이러한 REST 아키텍처의 제약 조건을 준수하여 설계된 API를 의미한다.
REST API의 구성 요소와 특징
1. 자원(Resource)
- 모든 것을 리소스로 표현하며, 각 리소스는 고유한 URI를 가진다.
- 리소스는 서버에 저장된 데이터, 이미지, 문서 등 모든 형태의 정보를 포함한다.
- 계층 구조를 가질 수 있으며, 복수형 명사를 사용하여 표현한다.
- 예시 URI 구조:
- 기본 형태: /users
- 특정 리소스: /users/123
- 계층 구조: /users/123/posts
- 필터링: /users?role=admin
- 정렬: /users?sort=name
2. 행위(Verb)
- HTTP 메서드를 통해 리소스에 대한 행위를 정의한다.
- 주요 HTTP 메서드의 특징:
- GET: 리소스 조회, 멱등성 보장, 캐시 가능
- POST: 리소스 생성, 멱등성 미보장, 캐시 불가
- PUT: 리소스 전체 교체, 멱등성 보장
- PATCH: 리소스 부분 수정, 멱등성 미보장
- DELETE: 리소스 삭제, 멱등성 보장
3. 표현(Representation)
- 클라이언트와 서버가 데이터를 주고받는 형태를 의미한다.
- JSON이 가장 많이 사용되며, XML, HTML 등도 사용 가능하다.
- 페이로드의 구조:
- 요청 데이터: HTTP 요청 본문에 포함
- 응답 데이터: 리소스의 상태를 반영
- 메타데이터: 헤더를 통해 전달
REST API 설계 원칙과 규칙
1. URI 설계 원칙
- 리소스는 명사를 사용하여 표현하며, 동사 사용은 피한다.
- 계층 관계는 슬래시(/)로 표현한다.
- URI는 소문자를 사용한다.
- 단어 구분은 하이픈(-)을 사용한다.
- 파일 확장자는 URI에 포함시키지 않는다.
잘못된 예시:
- /getUser/123
- /api/DELETE-user/123
- /api/users/123/createPost
올바른 예시:
- /users/123
- /users/123/posts
- /users/123/posts/comments
2. HTTP 메서드 활용 원칙
- 리소스에 대한 모든 행위는 HTTP 메서드로 표현한다.
- 각 메서드의 올바른 상황별 사용:
- GET: 데이터 검색, 조회
- POST: 새로운 데이터 생성
- PUT: 데이터 전체 교체
- PATCH: 데이터 부분 수정
- DELETE: 데이터 삭제
3. 상태 코드 활용 원칙
- HTTP 상태 코드를 목적에 맞게 명확하게 구분하여 사용한다.
- 주요 상태 코드 그룹:
- 200번대: 성공적인 응답
- 200 OK: 요청 성공
- 201 Created: 리소스 생성 성공
- 204 No Content: 요청 성공했지만 응답 데이터 없음
- 300번대: 리다이렉션
- 301 Moved Permanently: 영구 이동
- 304 Not Modified: 캐시된 리소스가 여전히 유효함
- 400번대: 클라이언트 에러
- 400 Bad Request: 잘못된 요청
- 401 Unauthorized: 인증 필요
- 403 Forbidden: 권한 없음
- 404 Not Found: 리소스를 찾을 수 없음
- 409 Conflict: 리소스 충돌
- 500번대: 서버 에러
- 500 Internal Server Error: 서버 내부 오류
- 503 Service Unavailable: 서비스 일시적 사용 불가
- 200번대: 성공적인 응답
JSON Server를 이용한 REST API 실습 상세 가이드
1. 환경 구축 단계
- 프로젝트 초기화와 설치:
- 프로젝트 디렉토리 생성
- npm init으로 package.json 생성
- JSON Server를 개발 의존성으로 설치
- 설정 파일 구성:
- package.json의 scripts 설정
- db.json 파일 생성 및 초기 데이터 구성
- 서버 실행 옵션:
- --watch: 파일 변경 감지
- --port: 포트 번호 지정
- --delay: 응답 지연 시간 설정
- --static: 정적 파일 제공 디렉토리 설정
2. HTTP 요청별 구현 상세
GET 요청 구현
- 전체 리소스 조회:
- URI 설계: /todos
- 응답 처리: 배열 형태의 전체 리스트
- 특정 리소스 조회:
- URI 설계: /todos/:id
- 응답 처리: 단일 객체 형태의 데이터
- 필터링과 정렬:
- 쿼리 파라미터 활용
- 예: /todos?completed=true&_sort=id&_order=desc
POST 요청 구현
- 리소스 생성 시 고려사항:
- Content-Type 헤더 설정 필수
- 요청 본문에 새로운 리소스 데이터 포함
- 응답으로 생성된 리소스 반환
- 유효성 검사:
- 필수 필드 확인
- 데이터 타입 검증
- 중복 데이터 확인
PUT/PATCH 요청 구현
- PUT vs PATCH 차이점:
- PUT: 전체 리소스 교체, 모든 필드 필요
- PATCH: 부분 수정, 변경할 필드만 전송
- 구현 시 주의사항:
- 리소스 존재 여부 확인
- 데이터 일관성 유지
- 적절한 응답 코드 반환
DELETE 요청 구현
- 삭제 처리 방식:
- 물리적 삭제 vs 논리적 삭제
- 연관 데이터 처리
- 삭제 후 응답 처리
3. 실무 적용시 고려사항
보안 관련
- 인증과 인가:
- JWT 토큰 활용
- OAuth 적용
- 접근 권한 관리
- CORS 설정:
- 허용할 도메인 설정
- 허용할 메서드 설정
- 인증 정보 처리
성능 최적화
- 캐싱 전략:
- ETag 활용
- Cache-Control 헤더 설정
- 조건부 요청 처리
- 페이지네이션:
- limit과 offset 활용
- 커서 기반 페이지네이션
- 요청/응답 최적화:
- 데이터 압축
- 필요한 필드만 선택적 응답
- 배치 처리 구현
에러 처리와 응답 표준화
- 에러 응답 형식 표준화
- 일관된 에러 응답 구조:
- 에러 코드: 시스템 내부적으로 식별 가능한 코드
- 에러 메시지: 사용자가 이해할 수 있는 메시지
- 상세 정보: 디버깅을 위한 추가 정보
- 주요 에러 상황별 처리:
- 유효성 검증 실패: 필드별 상세 오류 메시지 제공
- 인증/인가 실패: 명확한 사유와 해결 방법 안내
- 비즈니스 로직 오류: 구체적인 실패 원인 설명
- 응답 데이터 구조 표준화
- 성공 응답의 일관된 형식:
- 상태 정보: 요청 처리 결과
- 데이터: 실제 응답 데이터
- 메타 정보: 페이지네이션, 필터링 정보 등
- 컬렉션 응답 구조:
- 전체 개수
- 현재 페이지 정보
- 정렬 기준
- 필터링 조건
4. REST API의 확장과 발전
API 버전 관리
- 버전 관리 방식:
- URI 경로: /api/v1/users
- 헤더: Accept-Version
- 쿼리 파라미터: /api/users?version=1
- 하위 호환성 유지:
- 기존 API 동작 보장
- 점진적인 기능 추가
- 사용 중단(Deprecation) 정책
API 문서화
- API 문서화 도구:
- Swagger/OpenAPI
- API Blueprint
- Postman Documentation
- 문서에 포함될 내용:
- 엔드포인트 설명
- 요청/응답 예시
- 인증 방법
- 에러 코드 설명
- 변경 이력
모니터링과 로깅
- API 호출 모니터링:
- 응답 시간 측정
- 에러율 추적
- 사용량 통계
- 로깅 전략:
- 요청/응답 로그
- 에러 로그
- 성능 메트릭
- 보안 감사 로그
5. REST API 디자인 패턴과 모범 사례
리소스 관계 표현
- 중첩된 리소스:
- /users/{id}/posts
- /posts/{id}/comments
- 관계형 엔드포인트:
- /users/{id}/followers
- /users/{id}/following
벌크 작업 처리
- 여러 리소스 동시 처리:
- 벌크 생성: POST /bulk/users
- 벌크 수정: PUT /bulk/users
- 벌크 삭제: DELETE /users?ids=1,2,3
검색과 필터링
- 검색 파라미터:
- 전체 검색: /search?q=keyword
- 필드별 검색: /users?name=john
- 필터링 옵션:
- 복합 조건: /users?role=admin&status=active
- 범위 검색: /products?price_min=100&price_max=200
예상문제 [🔥]
https://github.com/junh0328/prepare_frontend_interview?tab=readme-ov-file
REST API가 뭔가요?
REST(Representational State Transfer)는 HTTP를 기반으로 클라이언트가 서버의 리소스에 접근하는 방식을 규정한 아키텍처입니다.
REST는 2000년에 로이 필딩이 HTTP의 장점을 최대한 활용할 수 있는 아키텍처로 제안했습니다. 당시 웹이 HTTP를 제대로 사용하지 못하고 있는 상황을 보고, HTTP 프로토콜의 의도에 맞게 설계하도록 유도하기 위해서였습니다.
REST API는 이러한 REST 아키텍처의 제약 조건을 준수하여 설계된 API를 의미합니다. 즉, REST API는 HTTP 기반으로 클라이언트가 서버의 리소스를 URI로 식별하고 HTTP 메서드를 통해 해당 리소스를 처리하는 방식을 정의한 인터페이스입니다.
이러한 REST의 기본 원칙을 성실히 지킨 서비스 디자인을 'RESTful'하다고 표현합니다.
REST API의 가장 큰 특징은 self-descriptiveness(자체 표현 구조, 셀프 디스크립티브니스)입니다. 이는 REST API만으로도 HTTP 요청의 내용을 이해할 수 있어야 한다는 것을 의미합니다. 예를 들어, '/users'라는 URI에 GET 요청을 보내면 사용자 목록을 조회한다는 것을 직관적으로 이해할 수 있습니다.
REST API의 구성은 어떤 것이 있나요?
REST API는 크게 세 가지 요소로 구성됩니다.
첫째, 자원(Resource)입니다. 모든 것을 리소스로 표현하며, 각 리소스는 URI로 식별됩니다. 예를 들어, 사용자 정보를 다루는 API에서 '/users'라는 URI는 사용자라는 리소스를 나타냅니다.
둘째, 행위(Verb)입니다. HTTP 메서드를 통해 리소스에 대한 행위를 정의합니다. 주요 메서드로는 GET(조회), POST(생성), PUT(전체 수정), PATCH(부분 수정), DELETE(삭제) 등이 있습니다.
셋째, 표현(Representation)입니다. 클라이언트가 자원의 상태에 대한 조작을 요청하면 서버가 응답하는 형태를 의미합니다. 주로 JSON 형식을 사용하며, 이는 페이로드를 통해 전달됩니다. 여기에는 실제 데이터뿐만 아니라 메타데이터도 포함될 수 있습니다.
REST API를 설계하는데 중요한 것이 있을까요?
REST API를 설계할 때 가장 중요한 두 가지 핵심 원칙이 있습니다.
첫 번째로, URI는 리소스를 표현하는데 집중해야 합니다. 여기서 중요한 점은 리소스를 식별할 때 동사가 아닌 명사를 사용해야 한다는 것입니다. 예를 들어 'getUsers'나 'deletePost'와 같이 행위를 나타내는 표현이 URI에 들어가서는 안 됩니다. 대신 '/users'나 '/posts/1'과 같이 리소스를 명확하게 표현해야 합니다.
두 번째로, 리소스에 대한 행위는 반드시 HTTP 메서드로 표현해야 합니다. 예를 들어 사용자를 삭제하고 싶다면 '/users/delete/1'과 같은 URI를 사용하는 게 아니라, '/users/1'이라는 URI에 DELETE 메서드를 사용해야 합니다.
이 2가지가 중심 규칙이라고 할 수 있으며, 추가로 고려해야 할 설계 원칙들도 있습니다.
- URI는 계층 관계를 잘 표현해야 합니다. 예를 들어 '/users/123/posts'처럼요.
- URI는 소문자를 사용하고, 단어 구분은 하이픈(-)을 사용합니다.
- URI 마지막에는 슬래시(/)를 포함하지 않습니다.
- 파일 확장자는 URI에 포함시키지 않습니다.
HTTP 요청 메서드에 대해서 아는대로 얘기해보세요
HTTP 요청 메서드는 클라이언트가 서버에게 요청의 종류와 목적을 알리는 방법입니다. 주요 메서드들과 그 특징을 설명드리겠습니다.
GET 메서드는 리소스를 조회할 때 사용합니다. 서버의 데이터를 변경하지 않는 읽기 전용 메서드이며, 요청 시 body에 데이터를 담지 않습니다. 성공적인 요청은 200(OK) 상태 코드를 반환합니다.
POST 메서드는 새로운 리소스를 생성할 때 사용합니다. 요청 시 body에 생성할 리소스의 데이터를 담아 보내며, 성공적인 생성은 201(Created) 상태 코드를 반환합니다.
PUT 메서드는 리소스를 완전히 대체할 때 사용합니다. 요청 시 리소스의 모든 필드를 포함한 데이터를 전송해야 하며, 해당 리소스가 없으면 새로 생성할 수도 있습니다.
PATCH 메서드는 리소스를 부분적으로 수정할 때 사용합니다. PUT과 달리 특정 필드만 수정할 수 있어서, 요청 시 변경할 필드만 전송하면 됩니다.
DELETE 메서드는 리소스를 삭제할 때 사용합니다. 일반적으로 body를 담아 보내지 않으며, 성공적인 삭제는 204(No Content) 상태 코드를 반환합니다.
특별히 GET, PUT, DELETE는 멱등성을 가진다는 특징이 있습니다. 멱등성이란 동일한 요청을 여러 번 보내도 서버의 상태가 동일하게 유지되는 성질을 말합니다. 반면 POST는 멱등성을 가지지 않습니다.
HTTP 상태 코드를 아는대로 말해주세요 🔥
HTTP 상태 코드는 서버가 클라이언트에게 요청의 처리 상태를 알려주는 숫자 코드입니다. 100번대부터 500번대까지 크게 다섯 가지 그룹으로 나뉩니다.
200번대는 성공적인 응답을 나타냅니다.
- 200(OK)는 요청이 성공적으로 처리되었음을 의미합니다.
- 201(Created)는 새로운 리소스가 성공적으로 생성되었을 때 사용됩니다.
- 204(No Content)는 요청은 성공했지만 응답 본문에 데이터가 없을 때 사용됩니다. 주로 DELETE 요청의 성공 응답으로 사용됩니다.
300번대는 리다이렉션과 관련됩니다.
- 301(Moved Permanently)은 요청한 리소스가 새로운 URI로 영구적으로 이동했음을 나타냅니다.
- 304(Not Modified)는 클라이언트가 캐시된 리소스를 계속 사용할 수 있음을 나타냅니다.
400번대는 클라이언트 오류를 나타냅니다.
- 400(Bad Request)는 잘못된 문법으로 인해 서버가 요청을 이해할 수 없는 경우입니다.
- 401(Unauthorized)는 인증이 필요한 리소스에 인증 없이 접근한 경우입니다.
- 403(Forbidden)은 권한이 없는 리소스에 접근할 때 발생합니다.
- 404(Not Found)는 요청한 리소스를 찾을 수 없는 경우입니다.
- 409(Conflict)는 리소스의 현재 상태와 충돌이 발생한 경우입니다.
500번대는 서버 오류를 나타냅니다.
- 500(Internal Server Error)는 서버에 오류가 발생한 경우입니다.
- 503(Service Unavailable)은 서버가 일시적으로 요청을 처리할 수 없는 상태입니다.
이러한 상태 코드들은 RESTful API를 설계할 때 매우 중요한 역할을 합니다. 각 상황에 맞는 적절한 상태 코드를 사용함으로써 클라이언트에게 더 명확한 피드백을 제공할 수 있고, 이는 API의 사용성과 신뢰성을 높이는 데 기여합니다.
'🧱 프론트엔드 주제 > JavaScript' 카테고리의 다른 글
[모던 자바스크립트 Deep Dive] 46장 - 제너레이터와 async/await (1) | 2024.11.30 |
---|---|
[모던 자바스크립트 Deep Dive] 45장 - Promise (0) | 2024.11.26 |
[모던 자바스크립트 Deep Dive] 43장 - Ajax (1) | 2024.11.19 |
[모던 자바스크립트 Deep Dive] 42장 - 비동기 프로그래밍 (0) | 2024.11.12 |
[모던 자바스크립트 Deep Dive] 41장 - 타이머 (0) | 2024.11.12 |