JSON Server로 가상 REST API 서버를 구축하여 HTTP 요청을 전송하고 응답 받는 연습을 했다.
JSON Server는 json 파일을 이용해 가상 REST API 서버를 구축할 수 있는 툴이다.
npm을 이용해 설치할 수 있다.
npm init -y
npm install json-server --save -dev
npm init의
-y
옵션
package.json 파일을 생성할 때, npm 프로젝트에 대한 기본 양식을 일일이 작성하지 않고 default 값으로 설정된 package.json 파일을 생성하고자 할 때 사용하는 옵션이다.
npm install의
—-save -dev
옵션
—save 옵션은 패키지와 버전을 package.json 파일의dependencies
에 저장하는 옵션이다. 이 옵션을 -dev 옵션과 사용하면 dependencies가 아닌devDependencies
에 저장한다.이때
dependencies
는 배포할 때 포함될 패키지,devDependencies
는 개발할 때만 필요한 패키지 정보를 담고 있다. 따라서npm install
을 하면 기본적으로 dependencies에 들어가고, 별도로 옵션(—save -dev)을 줘야 devDependencies에 들어간다.
JSON Server에서 데이터베이스 역할을 할 파일을 만든다.
touch db.json
nano 편집기를 열어 내용을 작성했다.
nano db.json
{
"todos": [
{
"id": 1,
"content": "HTML",
"completed": true
},
{
"id": 2,
"content": "CSS",
"completed": false
},
{
"id": 3,
"content": "JavaScript",
"completed": true
}
]
}
다음 명령어를 입력해 서버를 실행할 수 있다. 기본 포트는 3000이며, 포트를 변경하려면 —port {포트 번호}
옵션을 추가하면 된다.
json-server --watch db.json
—-watch
옵션
—watch는 파일의 변화를 감시하는 옵션이다.
그런데 서버를 설치하고 서버 실행 명령어를 입력했으나 서버가 실행되지 않았다.그래서 npm start 명령어로 실행해 보려고 package.json의 scripts를 수정했다.
"scripts": {
"start": "json-server --watch db.json"
}
수정한 다음 npm start
로 서버를 실행시켰더니 되는 듯 했으나…
db.json 파일에 올바르지 않은 형식이 있다고 해서 열어봤더니
무의식적으로 붙인 trailing comma
가 있었다.
JSON에서는 trailing comma를 허용하지 않는다.
이걸 삭제했더니
서버가 잘 실행되었다!
나는 npm start로 실행시켰지만, 다른 방법으로는 다음 두 가지가 더 있으니 원하는 방법으로 하면 될 듯.
npm install -g json-server
npx json-server --watch db.json
XMLHttpRequest 객체로 HTTP 요청을 보내려 한다.
XMLHttpRequest 객체는 서버와 상호작용할 때 사용하며, 페이지의 새로고침 없이도 URL에서 데이터를 가져올 수 있다. 사용하게 될 메서드와 프로퍼티를 간단히 정리하면,
xhr.open(method, url)
: HTTP 요청을 초기화한다.xhr.setRequestHeader(header, value)
: HTTP 요청의 헤더 값을 지정한다.xhr.send(body)
: HTTP 요청을 전송한다. 페이로드가 필요한 요청의 경우 body에 작성하면 된다.xhr.onload
: HTTP 요청이 성공적으로 완료된 경우 실행할 이벤트 핸들러다.xhr.status
: HTTP 요청에 대한 (숫자로 된) 응답 상태다.xhr.statusText
: HTTP 서버로부터 받은 응답 상태 메시지다.xhr.response
: HTTP 요청에 대한 응답 값이다.GET은 엔드포인트의 모든 리소스를 취득할 때 사용한다.
get_index.html
파일을 작성하고 브라우저에서 http://localhost:포트번호/get_index.html
에 접속한다.
<!DOCTYPE html>
<html lang="en">
<body>
<pre></pre>
<script>
// XMLHttpRequest 객체 생성
const xhr = new XMLHttpRequest();
// HTTP 요청 초기화 - todos 리소스에서 모든 todos를 취득
xhr.open('GET', '/todos');
// HTTP 요청 전송
xhr.send();
// HTTP 요청이 성공적으로 완료됐다면 실행할 이벤트
xhr.onload = () => {
// status 프로퍼티 값이 200이면 정상적으로 응답된 것임
if (xhr.status === 200) {
document.querySelector('pre').textContent = xhr.response;
} else {
console.error('Error', xhr.status, xhr.statusText);
}
};
</script>
</body>
</html>
브라우저에서 확인하면 db.json 파일의 내용이 전부 가져와졌음을 알 수 있다.
성공적으로 가져왔기 때문에 응답 status는 200(OK)
이 되며, 새로고침을 하면 응답이 수정되지 않았기 때문에 status는 응답의 캐시된 버전을 사용한다는 304(Not Modified)
이다.
get_retrieve.html
파일을 작성하고 브라우저에서 http://localhost:포트번호/get_retrieve.html
에 접속한다.
<!DOCTYPE html>
<html lang="en">
<body>
<pre></pre>
<script>
// XMLHttpRequest 객체 생성
const xhr = new XMLHttpRequest();
// HTTP 요청 초기화 - todos 리소스에서 1번 todo 취득
xhr.open('GET', '/todos/1');
// HTTP 요청 전송
xhr.send();
// HTTP 요청이 성공적으로 완료됐다면 실행할 이벤트
xhr.onload = () => {
if (xhr.status === 200) {
document.querySelector('pre').textContent = xhr.response;
} else {
console.error('Error', xhr.status, xhr.statusText);
}
};
</script>
</body>
</html>
브라우저에서 확인하면 id가 1인 todo만을 가져왔음을 알 수 있다.
성공적으로 가져왔기 때문에 status는 200(OK)
이다.
만약 다음과 같이 없는 id를 가져오려 한다면
xhr.open('GET', '/todos/0');
status는 404(Not Found)
이다.
POST는 엔드포인트 리소스에 새로운 리소스를 생성할 때 사용한다.
새로 생성할 리소스를 서버에 보내야 하므로 setRequestHeader 메서드
를 사용해 서버로 전송할 페이로드의 MIME 타입
을 지정해야 한다. 보낼 내용(페이로드)은 send 메서드
에 담는다.
MIME 타입
: 미디어 타입 즉, 데이터의 형식을 말한다.
post.html
파일을 작성하고 브라우저에서 http://localhost:포트번호/post.html
에 접속한다.
<!DOCTYPE html>
<html lang="en">
<body>
<pre></pre>
<script>
// XMLHttpRequest 객체 생성
const xhr = new XMLHttpRequest();
// HTTP 요청 초기화 - todos 리소스에 새로운 todo 생성
xhr.open('POST', '/todos');
// 요청 body에 담아 서버로 전송할 페이로드의 MIME 타입 지정
xhr.setRequestHeader('content-type', 'application/json');
// HTTP 요청 전송 - 새로운 todo 생성 위해 페이로드 전송 필요
xhr.send(JSON.stringify({ id: 4, content: 'Angular', completed: false }));
// HTTP 요청이 성공적으로 완료됐다면 실행할 이벤트
xhr.onload = () => {
if (xhr.status === 200 || xhr.status === 201) {
document.querySelector('pre').textContent = xhr.response;
} else {
console.error('Error', xhr.status, xhr.statusText);
}
};
</script>
</body>
</html>
브라우저에는 생성한 todo의 내용이 나타났다.
이전과 다른 응답 status가 왔는데, 201(Created)
은 요청이 성공적이었으며 그 결과로 새로운 리소스가 생성되었음을 알리는 status다. 즉, 새로운 리소스가 생길만한 요청인 POST 또는 (일부)PUT에 따라올 수 있는 상태값이다.
여기서 페이지 새로고침을 한면 응답 status가 500(Internal Server Error)
이 된다. 이는 서버가 처리 방법을 모르는 상황임을 나타내는 값인데, 서버 에러를 총칭하는 응답(적합한 에러 status가 없을 때 보내는 응답)이기도 하다.
에러 메시지를 좀 더 살펴보면, 이미 존재하는 id로 새로운 리소스를 추가하려고 해서 에러가 발생한 상황임을 알 수 있다.
PUT은 특정 리소스 전체를 교체할 때 사용한다.
교체할 리소스를 서버에 보내야 하므로 setRequestHeader 메서드
를 사용해 서버로 전송할 페이로드의 MIME 타입
을 지정해야 한다. 보낼 내용(페이로드)은 send 메서드
에 담는다.
put.html
파일을 작성하고 브라우저에서 http://localhost:포트번호/put.html
에 접속한다.
<!DOCTYPE html>
<html lang="en">
<body>
<pre></pre>
<script>
// XMLHttpRequest 객체 생성
const xhr = new XMLHttpRequest();
// HTTP 요청 초기화 - id가 4인 todo의 리소스 교체(교체 대상에서 id는 제외함)
xhr.open('PUT', '/todos/4');
// 요청 body에 담아 서버로 전송할 페이로드의 MIME 타입 지정
xhr.setRequestHeader('content-type', 'application/json');
// HTTP 요청 전송 - 기존 todo의 내용을 교체하기 위해 페이로드 전송 필요
xhr.send(JSON.stringify({ id: 4, content: 'React', completed: true }));
// HTTP 요청이 성공적으로 완료됐다면 실행할 이벤트
xhr.onload = () => {
if (xhr.status === 200) {
document.querySelector('pre').textContent = xhr.response;
} else {
console.error('Error', xhr.status, xhr.statusText);
}
};
</script>
</body>
</html>
기존에 Angular, false였던 값이 React, true로 변경되었다.
응답 status는 200(OK)
이다.
PATCH는 특정 리소스의 일부를 수정할 때 사용한다.
수정할 리소스를 서버에 보내야 하므로 setRequestHeader 메서드
를 사용해 서버로 전송할 페이로드의 MIME 타입
을 지정해야 한다. 보낼 내용(페이로드)은 send 메서드
에 담는다.
patch.html
파일을 작성하고 브라우저에서 http://localhost:포트번호/patch.html
에 접속한다.
<!DOCTYPE html>
<html lang="en">
<body>
<pre></pre>
<script>
// XMLHttpRequest 객체 생성
const xhr = new XMLHttpRequest();
// HTTP 요청 초기화 - id가 4인 todo의 리소스 수정
xhr.open('PATCH', '/todos/4');
// 요청 body에 담아 서버로 전송할 페이로드의 MIME 타입 지정
xhr.setRequestHeader('content-type', 'application/json');
// HTTP 요청 전송 - 기존 todo의 내용을 수정하기 위해 페이로드 전송 필요
xhr.send(JSON.stringify({ completed: false }));
// HTTP 요청이 성공적으로 완료됐다면 실행할 이벤트
xhr.onload = () => {
if (xhr.status === 200) {
document.querySelector('pre').textContent = xhr.response;
} else {
console.error('Error', xhr.status, xhr.statusText);
}
};
</script>
</body>
</html>
true였던 값이 false로 변경되었다.
응답 status는 200(OK)
이다.
DELETE는 엔드포인트 리소스에서 특정 리소스를 삭제할 때 사용한다.
delete.html
파일을 작성하고 브라우저에서 http://localhost:포트번호/delete.html
에 접속한다.
<!DOCTYPE html>
<html lang="en">
<body>
<pre></pre>
<script>
// XMLHttpRequest 객체 생성
const xhr = new XMLHttpRequest();
// HTTP 요청 초기화 - id가 4인 todo 삭제
xhr.open('DELETE', '/todos/4');
// HTTP 요청 전송
xhr.send();
// HTTP 요청이 성공적으로 완료됐다면 실행할 이벤트
xhr.onload = () => {
if (xhr.status === 200) {
document.querySelector('pre').textContent = xhr.response;
} else {
console.error('Error', xhr.status, xhr.statusText);
}
};
</script>
</body>
</html>
id가 4인 todo가 삭제되었다.
응답 status는 200(OK)
이다.
여기서 페이지 새로고침을 하면 응답 status가 404(Not Found)
가 된다. id가 4인 리소스는 이미 삭제되었기 때문에 /todos/4
라는 엔드포인트를 참조할 수 없게 되어 나타나는 에러다.
REST API 서버를 이용해 CRUD를 위한 HTTP 요청을 보내는 연습 끝!
다음엔 postman을 써 볼까 한다.
[Reference] 모던 자바스크립트 Deep Dive