REpresentational State Transfer
의 약자
웹의 HTTP
의 장점을 활용한 클라이언트가 서버의 리소스에 접근하는 방식을 규정한 아키텍처
를 의미한다.
REST API
는 REST
를 기반으로 서비스 API
를 구현한 것을 의미한다.
REST API
는 자원
, 행위
, 표현
으로 구성되며, HTTP
요청의 내용을 이해할 수 있다.
구성 요소 | 내용 | 표현 방법 |
---|---|---|
자원 (Resource) | 자원 | URI(엔드 포인트) |
행위 (Verb) | 자원에 대한 행위 | HTTP 요청 메서드 |
표현(Representations) | 자원에 대한 행위의 구체적 내용 | 페이로드 |
URI
는 리소스를 표현하는데 집중한다.메서드
는 HTTP 요청 메서드를 통한다.URI
는 리소스를 표현하는데 중점을 둬야하며, 리소스를 식별할 수 있는 이름은 동사보다 명사를 사용한다.
따라서, 이름에 get
같은 행위에 대한 표현이 들어가서는 안된다.
# BAD
GET / getTodos / 1 --- get X
GET / todos / show / 1 --- show X
# GOOD
GET / todos / 1
HTTP 요청 메서드
는 클라이언트
가 서버
에게 요청의 종류
와 목적(리소스에 대한 행위)
을 알리는 방법이다.
메서드는 GET
, POST
, PUT
, PATCH
, DELETE
로 구성되며, CRUD
를 구현한다.
HTTP 요청 메서드 | 종류 | 목적 | 페이로드 |
---|---|---|---|
GET | index/retrieve | 모든 혹은 특정 리소스 취득 | X |
POST | create | 리소스 생성 | O |
PUT | replace | 리소스의 전체 교체 | O |
PATCH | modify | 리소스의 일부 수정 | O |
DELETE | delete | 모든 혹은 특정 리소스 삭제 | X |
리소스에 대한 행위는 HTTP 요청 메서드
를 통해 표현하며 URI
를 표현하지 않는다.
예를 들어 리소스를 취득하는 경우에는 GET
, 리소스를 삭제하는 경우에는 DELETE
를 사용하여 리소스에 대한 행위를 명확히 표현한다.
# BAD
GET / todos / delete / 1
# GOOD
DELETE / todos / 1
HTTP 요청
을 전송하고 응답을 받으려면 서버가 필요하나다.
JSON Server
를 사용해서 가상 REST API
서버를 구축하여 HTTP
요청을 전송하고 응답을 받는 실습을 진행해본다.
npm
을 이용해서 json-server
를 로컬 설치한다.
mkdir json-server-exam && json-server-exam
npm init -y
npm install json-server --save-dev
root
폴더 아래에 db.json
파일을 생성한다. 해당 파일은 데이터베이스 역할을 한다.
{
"todos": [
{
"id": 1,
"content": "HTML",
"completed": true
},
{
"id": 2,
"content": "CSS",
"completed": false
},
{
"id": 3,
"content": "Javascript",
"completed": true
}
],
"users": [
{
"id": 1,
"name": "Lee",
"role": "developer"
},
{
"id": 2,
"name": "Kim",
"role": "designer"
}
]
}
package.json
내 script
에 json-server
관련 스크립트를 추가한다.
// package.json
...
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "json-server --watch db.json"
},
...
npm run start
localhost:3000
JSON-SERVER
에서 읽는 파일을 별도로 지정할 수 있다.
경로는 ./public/index.html
파일이다.
// index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<pre></pre>
<script>
const XHR = new XMLHttpRequest()
XHR.open(`GET`, `/todos`)
XHR.send()
XHR.onload = () => {
if(XHR.status == 200){
document.querySelector(`pre`).textContent = XHR.response
}else {
console.log(`error`, XHR.status, XHR.statusText)
}
}
</script>
</body>
</html>
POST
요청<script>
const XHR = new XMLHttpRequest();
XHR.open(`POST`, `/todos`);
XHR.setRequestHeader(`Content-Type`, `application/json`);
XHR.send(JSON.stringify({ id: 4, content: "React", complete: true }));
XHR.onload = () => {
if (XHR.status == 200 || XHR.status === 201) {
document.querySelector(`pre`).teßxtContent = XHR.response;
} else {
console.log(`error`, XHR.status, XHR.statusText);
}
};
</script>
PUT
요청<script>
const XHR = new XMLHttpRequest();
XHR.open(`PUT`, `/todos/4`);
XHR.setRequestHeader(`Content-Type`, `application/json`);
XHR.send(JSON.stringify({ id: 4, content: "React-2", complete: true }));
XHR.onload = () => {
if (XHR.status == 200) {
document.querySelector(`pre`).teßxtContent = XHR.response;
} else {
console.log(`error`, XHR.status, XHR.statusText);
}
};
</script>
PATCH
요청<script>
const XHR = new XMLHttpRequest();
XHR.open(`PATCH`, `/todos/4`);
XHR.setRequestHeader(`Content-Type`, `application/json`);
XHR.send(JSON.stringify({ content: "React-3" }));
XHR.onload = () => {
if (XHR.status == 200) {
document.querySelector(`pre`).teßxtContent = XHR.response;
} else {
console.log(`error`, XHR.status, XHR.statusText);
}
};
</script>
DELETE
요청<script>
const XHR = new XMLHttpRequest();
XHR.open(`DELETE`, `/todos/4`);
XHR.send();
XHR.onload = () => {
if (XHR.status == 200) {
document.querySelector(`pre`).teßxtContent = XHR.response;
} else {
console.log(`error`, XHR.status, XHR.statusText);
}
};
</script>