나는 먼저 기능을 구현한 후에 데이터베이스와 연동해서 데이터를 저장했다. 데이터베이스에 연동하기 전까지는 우선 메모리에 저장하도록 했다.
회원가입을 하는데 2가지 조건이 있다.
만약 두가지 조건에 부합하지 않는다면 회원가입에 실패한다.
app.js
// 사용자 정보를 담을 배열
const users = [];
// 회원가입
app.post('/user/register', (req, res) => {
const { id, password, name } = req.body;
// TODO id, password, name이 있는지 체크한다.
if (!id || !password || !name) {
res.status(400).send({ message: 'id, password, name은 필수입력 사항입니다.' });
return;
}
// TODO id는 중복되지 않도록한다.
const user = users.find((user) => user.id === id);
if (user) {
res.status(400).send({ message: '이미 존재하는 아이디입니다.' });
return;
}
// TODO 사용자를 추가한다.
users.push(req.body);
res.send({ message: '사용자를 등록했습니다.' });
});
회원가입 기능을 구현했으니, 잘 되는지 확인해보기 위해 API 테스트를 해보자.
Postman, Talend API 등 좋은 툴들이 많지만 나는 vscode에서 바로 사용할 수 있는 확장앱인 REST Client를 자주 사용하고 있다.
확장앱을 설치하고 나서, .http 확장자를 사용해서 파일을 생성하고 아래처럼 http request를 작성해보자.
# Method, Path
POST http://localhost:3001/user/register
# Headers
Content-Type: application/json
# Body
{
"id": "test1",
"name": "테스트1",
"password": "qwer"
}
메소드 위에 'Send Request' 버튼을 클릭해서 http 요청을 보낼 수 있다.
처음 요청을 보내면, test1이라는 id를 사용하는 사용자가 없기때문에 무사히 회원가입에 성공한다.
요청을 한번 더 보내면 이미 존재하는 아이디이기 때문에 회원가입에 실패한다.
로그인을 할 때는 id와 password를 받아서 두 가지를 체크한다.
만약 아이디가 존재하지 않거나, 비밀번호가 일치하지 않으면 로그인에 실패한다. 로그인 성공 시, 토큰을 반환해서 프론트엔드에서 로그인을 오래동안 유지할 수 있도록 할 예정이다.
app.js
app.post('/user/login', (req, res) => {
const { id, password } = req.body;
// TODO id, password가 있는지 체크한다.
if (!id || !password) {
res.status(400).send({ message: 'id, password는 필수입력 사항입니다.' });
return;
}
// TODO 입력받은 id의 사용자를 찾는다.
const user = users.find((user) => user.id === id);
if (!user) {
res.status(400).send({ message: '존재하지 않는 사용자입니다.' });
return;
}
// TODO 입력받은 password와 찾은 사용자의 password가 일치하는지 체크한다.
if (user.password !== password) {
res.status(400).send({ message: '비밀번호가 일치하지 않습니다.' });
return;
}
// TODO 토큰을 발급한다.
res.status(200).send({ token: 'token' });
});
나는 토큰 발급을 위해 jsonwebtoken 라이브러리를 사용했다.
$ npm i jsonwebtoken
서버는 토큰이 유효할 경우에만 로그인 상태라고 생각하고, 토큰이 유효하지 않으면 글 등록, 수정, 삭제 등의 기능을 제한할거다.
토큰 기능은 따로 jwt 폴더에 파일을 생성해서 관리했다.
jwt/index.js
const jwt = require('jsonwebtoken');
const tokenService = {
// TODO 토큰 발급
getToken(user_id) {
// 토큰에 담을 정보, 사용할 키 (아무 값이나 가능), 토큰 옵션
return jwt.sign({ user_id }, 'SECRET_KEY', {
expiresIn: '1d' // 만료시간
});
},
// TODO 토큰이 유효하다면 토큰에 담긴 정보를 반환
getPayload(token) {
return jwt.verify(token, 'SECRET_KEY');
}
}
module.exports = tokenService;
이제 로그인 기능에서 토큰 발급을 해서 반환하도록 하면 된다.
app.js
const tokenService = require('./jwt');
app.post('/user/login', (req, res) => {
const { id, password } = req.body;
// ...
// TODO 토큰을 발급한다.
res.status(200).send({ token: tokenService.getToken(id) });
});
로그인 API를 테스트 하려고 하는데, 서버를 계속해서 재시작해서 기존 데이터가 사라져서 불편하다. 기본 사용자 정보를 배열에 저장한 후에 테스트를 진행했다.
const users = [
{
id: 'test',
name: 'tester',
password: 'test'
}
];
.http
POST http://localhost:3001/user/login
Content-Type: application/json
{
"id": "test",
"password": "test"
}
응답으로 토큰을 잘 발급해주고 있다.
그런데 서버를 실행시키는 app.js 파일이 꽤 복잡해졌다. app.js는 서버를 실행시키는 코드만 남기고, 라우터를 관리하는 파일을 따로 생성해서 관심사를 분리해보자!
user 폴더를 생성하고 index.js 파일을 만들었다.
라우터를 분리하기 위해서는 express의 Router 함수로 라우터를 생성해서 사용하면 된다.
user/index.js
const express = require('express');
const router = express.Router();
// app이 아닌 router!
router.post('/login', (req, res) => {
// ...
});
router.post('/register', (req, res) => {
// ...
});
module.exports = router;
그리고 기존에 app.js에서는 userRouter를 불러와서 넣어주기만 하면 된다.
app.js
const userRouter = require('./user');
app.use('/user', userRouter);
app.js가 매우 깔끔해졌다. ^0^