json-server 커스텀이 필요했던 이유
react를 redux-toolkit을 공부하면서 간단하게 crud를 실습해야했기 때문에
간단하게 json-server를 이용하기로 했다.
json-server에서 지원해주는 기능으로 간단한 crud는 손쉽게 이용할 수 있다.
필요한 것도 db로 필요한 것도 json파일 하나 뿐이기 때문에 어려울 것이 없다.
당연하게도 이 간단한 기능에는 한계가 있었는데
GET으로는 read만 가능하고 POST로는 생성만 가능했던 것.
그게 왜 문제냐고 할 수 있는데, 비밀번호가 맞는지 확인한다고 하면,
GET 방식으로 query string에 비밀번호를 넣어서 보내야하는 치명적인 문제점이 발생하게 된다.
(물론 실습이니까 그냥 넘어갈 수도 있었는데 용납할 수가 없었다.)
사용자 인증 관련 기능이 추가된 json-server인 json-server-auth라는 라이브러리도 존재하지만
내가 사용하려는 기능은 로그인이 없는 익명 게시판이었기 때문에 필요한 스펙이 아니었다.
그러면 어떻게하면 될까?
그렇다.
커스텀하면 된다.
커스텀 시작하기
제일 먼저 db로 사용할 json파일을 생성해주자.
간단한 익명 게시판에는 posts와 comments 두 가지의 프로퍼티만 필요하다.
// db.json
{
"posts": [],
"comments": []
}
json-server의 기본 기능만 이용하려면 db.json에 객체 내부에 필요한 키를 적절히 넣어두고 다음 명령어를 실행하면 된다.
// db.json파일로 json-server를 3000 port에 실행
$ json-server --watch db.json --port 3000
package.json 내부에 script를 작성해주어서 커맨드를 설정해주어도 된다.
{
"scripts": {
"start": "json-server --watch db.json"
},
}
이제 커스텀하기 위해서는 server.js파일을 생성해준다.
// server.js
const jsonServer = require('json-server');
const server = jsonServer.create();
const router = jsonServer.router('db.json');
const middlewares = jsonServer.defaults();
// Set default middlewares (logger, static, cors and no-cache)
server.use(middlewares);
// Use default router
server.use(router);
server.listen(3000, () => {
console.log('JSON Server is running')
});
위 코드가 json-server의 기본 기능에서 아무것도 건드리지 않은 기본 코드이다.
여기다가 필요한 기능을 하나씩 추가해보도록 하자.
DB 조작하는 방법
db.json의 데이터를 조작하려면 필요한 라이브러리가 있다.
lowdb라는 라이브러리를 추가해주자.
npm install lowdb@1.0.0
🖐🏻왜 1.0.0 버전을 다운 받나요?
최신 버전에서는 ES Module import 방식을 이용해야만 한다.
그렇지 않으면 RR_REQUIRE_ESM : Must use import to load ES Module 오류가 발생한다.
프로젝트 특성상 ES Module import 방식을 이용할 수 없어서 1.0.0 버전으로 진행한다.
깃허브 이슈 : https://github.com/typicode/lowdb/issues/480
server.js에 다음 코드를 추가하면 이제 lowdb를 이용해서 db.json을 조작할 수 있다.
const low = require('lowdb');
const FileSync = require('lowdb/adapters/FileSync');
// db.json를 조작하기 위해 lowdb를 사용
const low = require('lowdb');
const FileSync = require('lowdb/adapters/FileSync');
const adapter = new FileSync('db.json');
const db = low(adapter);
Request body 읽기
request body는 그냥 꺼내서 읽을 수 없다.
request의 데이터를 이용하기 위해서는 파싱 작업이 필요하다.
// json-server body parser
server.use(jsonServer.bodyParser);
json-server에서는 body parser가 내장되어 있기 때문에 다음 코드 라인을 한줄만 추가해주면 request body를 읽을 수 있다.
기능 추가하기
post 메소드로 password를 request에 넣어서 보내는 요청을 처리해보자.
요청 url은 /auth/posts/:id로 설정했다.
게시글의 아이디를 받아서 비밀번호 정보와 같은지 확인한 뒤
맞으면 true를 틀리면 false를 보내는 간단한 코드이다.
db.json을 lowdb의 기능을 통해서 읽어서 찾은 뒤 존재하는지 확인한다.
server.post('/auth/posts/:id', (req, res) => {
const { id } = req.params;
const { password } = req.body;
const data = db
.get('posts')
.find({
id: Number(id),
password,
})
.value();
if (data) {
res.send({ result: true, message: 'success' });
} else {
res.send({ result: false, message: 'failed' });
}
});
댓글 쪽도 동일한 코드로 작성하면 된다.
// 실행 코드
$ node server.js
server.js에 json-server 실행시켜주기 때문에 server.js만 실행해주면 된다.
업데이트가 안되는 문제
이렇게만 한다면 db.json에 동일한 id의 password를 가진 데이터가 있어도 값을 제대로 읽어오지 못하는 문제가 발생한다.
그 이유는 lowdb로 읽어온 db.json의 상태와 server.use(router)를 이용해서 json-server의 기능을 이용해서 업데이트한 db.json의 상태가 같지 않기 때문이다.
이 문제를 해결하기 위해서는 lowdb를 이용하기 전에lowdb가 읽은 db.json의 상태를 업데이트해주면 된다.
이 부분은 db.json의 상태를 읽어오는 코드이다.
adapter = new FileSync('db.json');
db = low(adapter);
해당 부분을 함수로 만들어 준 다음 요청을 처리하기 이전에 호출해주면 된다.
let adapter;
let db;
const setDB = () => {
adapter = new FileSync('db.json');
db = low(adapter);
};
server.post('/auth/comments/:id', (req, res) => {
setDB();
// ...
json-server를 사용하기 전에...
대부분 실습용으로 사용하는 json-server이기 때문에 기본적인 기능을 파악하지 않고 사용하는 경우가 더러 있는 것 같다.
깃허브 리드미에 기능이 자세하게 설명되어 있으니 꼭 파악하고 사용하도록 하자.
server.js 전체 코드
/* eslint-disable import/no-unresolved */
const jsonServer = require('json-server');
const low = require('lowdb');
const FileSync = require('lowdb/adapters/FileSync');
const server = jsonServer.create();
const router = jsonServer.router('db.json');
const middlewares = jsonServer.defaults();
// db.json를 조작하기 위해 lowdb를 사용
let adapter;
let db;
const setDB = () => {
adapter = new FileSync('db.json');
db = low(adapter);
};
server.use(jsonServer.bodyParser);
server.use(middlewares);
server.post('/auth/comments/:id', (req, res) => {
setDB();
const { id } = req.params;
const { password } = req.body;
const data = db
.get('comments')
.find({
id: Number(id),
password,
})
.value();
if (data) {
res.send({ result: true, message: 'success' });
} else {
res.send({ result: false, message: 'failed' });
}
});
server.post('/auth/posts/:id', (req, res) => {
setDB();
const { id } = req.params;
const { password } = req.body;
const data = db
.get('posts')
.find({
id: Number(id),
password,
})
.value();
if (data) {
res.send({ result: true, message: 'success' });
} else {
res.send({ result: false, message: 'failed' });
}
});
server.use(router);
server.listen(3001, () => {
console.log('JSON Server is running');
});
🌐레퍼런스
https://github.com/typicode/json-server
https://poiemaweb.com/json-server
https://github.com/typicode/lowdb/tree/v1.0.0
https://opentutorials.org/module/4315/26579
'react' 카테고리의 다른 글
[React] Github Actions로 CI/CD 적용하기 (1) | 2023.01.05 |
---|---|
[Vite] vite로 이유 모르게 웹소켓 통신이 안되는 경우(ws, sockjs) (1) | 2023.01.05 |
[React] Lifecycle과 메소드 그리고 Hook (0) | 2022.12.12 |
[React] Redux-toolkit 입문하기 (0) | 2022.12.10 |
[React] 카운터로 시작하는 Redux (0) | 2022.12.04 |