Node.js로 Mock API 서버를 만들어 보자
- Published on
백엔드 개발자가 api를 전달해주기 전에 간단하게나마 로그인, 로그아웃 그리고 mock 데이터를 뿌려주는 서버가 있었으면 해서 Express를 사용해서 만들어보겠습니다.
Node.js와 Express를 사용하여 더미 데이터를 뿌려주고 로그인/로그아웃 기능은 express-session을 이용하여 구현한 Mock API 서버입니다.
환경 설정 및 필요 모듈 설치
mkdir api-server // 프로젝트 폴더 생성
cd api-server
yarn init -y
yarn add express express-session cors cookie-parser
yarn add -D nodemon
express
: 웹 서버를 구축하기 위한 프레임워크express-session
: 로그인/로그아웃 처리cookie-parser
: 쿠키 파싱cors
: 크로스-오리진 리소스 공유nodemon
: 개발 중 서버의 자동 재시작을 위한 도구
app.js
const express = require('express');
const session = require('express-session');
const cors = require('cors');
const cookieParser = require('cookie-parser');
const app = express();
const PORT = 9090;
const route = require('./route');
app.use(express.json()); // JSON 형태의 요청 body를 파싱하기 위한 미들웨어
// HTTP POST 요청의 본문(body)에 인코딩된 데이터를 해석하고, req.body 객체에 채워넣어주는 역할을 합니다.
// extended: false는 라이브러리 querystring을 사용한다는 의미입니다.
// 클라이언트로부터 전송된 URL 인코딩된 폼 데이터를 쉽게 사용할 수 있도록 해주는 함수입니다.
// 이를 통해 개발자는 별도의 파싱 작업 없이 요청 데이터에 접근할 수 있습니다.
app.use(express.urlencoded({ extended: false }));
// cookie-parser는 클라이언트로부터 오는 HTTP 요청에 포함된 쿠키를 파싱(parse)하여 사용할 수 있게 만드는 미들웨어
app.use(cookieParser());
app.use(
cors({
origin: 'http://localhost:3000',
credentials: true,
preflightContinue: false,
optionsSuccessStatus: 204,
}),
);
app.use(
session({
secret: 'your-secret-key', // 이 부분은 보안을 위해 복잡한 문자열로 설정해야 합니다.
name: 'sessionId',
resave: false,
rolling: true,
saveUninitialized: false,
cookie: {
secure: false,
httpOnly: true,
maxAge: 1800000,
},
}),
);
app.use('/', route);
app.listen(PORT, () => {
console.log(`서버가 ${PORT}번 포트에서 실행중입니다.`);
});
app.use((err, req, res, next) => {
res.status(err.status || 500).json({ error: '에러가 발생했습니다.' });
});
middleware.js
// middleware
function isAuthenticated(req, res, next) {
console.log('user', req.session.user);
console.log('cookies', req.cookies);
if (req.session.user) {
return next();
}
return res.status(401).json({ message: '로그인이 필요합니다.' });
}
module.exports = {
isAuthenticated,
};
route.js
const express = require('express');
const router = express.Router();
const { isAuthenticated } = require('./middleware');
// 로그인
router.post('/login', (req, res) => {
const { username, password } = req.body;
if (username === 'username' && password === 'password') {
req.session.user = { username };
res.status(200).end();
} else {
res.status(400).json({ message: 'username/password가 일치하지 않습니다.' });
}
});
// 로그아웃
router.get('/logout', (req, res) => {
req.session.destroy((err) => {
if (err) {
return res.status(401).end('로그아웃 중 에러 발생');
}
res.status(200).send('로그아웃 성공');
});
});
// 로그인 여부 확인
router.get('/api/auth', isAuthenticated, (req, res) => {
return res.status(200).json({ test: true });
});
router.get('/api/channels', (req, res, next) => {
return res.json([{ channelId: 1 }, { channelId: 2 }]);
});
router.post('/api/channels', (req, res, next) => {
return res.json({ success: true });
});
router.patch('/api/channels', (req, res, next) => {
return res.json({ success: true });
});
router.put('/api/channels', (req, res, next) => {
return res.json({ success: true });
});
module.exports = router;
package.json
{
"name": "api-server",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"dev": "nodemon app.js"
},
"dependencies": {
"cookie-parser": "^1.4.6",
"cors": "^2.8.5",
"express": "^4.18.2",
"express-session": "^1.17.3"
},
"devDependencies": {
"nodemon": "^3.0.2"
}
}
Mock API 서버 실행
yarn dev
간단한 Mock API 서버를 구현해보았습니다.
사용한 모듈에 대해서는 아래에서 설명하겠습니다.
express-session
express-Session은 클라이언트와 서버 간의 상태를 유지하는 세션 데이터를 관리하기 위한 미들웨어입니다. 클라이언트가 서버에 요청을 할 때마다, 서버는 클라이언트에게 고유한 세션 ID를 부여합니다. 이 ID는 쿠키에 저장되어 클라이언트의 브라우저에 남아 있으며, 클라이언트가 서버에 요청을 보낼 때마다 이 ID를 함께 보내 서버가 클라이언트를 식별할 수 있게 합니다.
yarn add express-session
const app = express();
const session = require("express-session");
...
app.use(
session({
secret: "your-secret-key", // 세션을 암호화하기 위한 비밀키입니다. 보안을 위해 복잡하고 예측 불가능한 문자열을 사용해야 합니다.
name: "sessionId", // 쿠키의 이름
resave: false, // 세션 데이터가 변경되지 않았더라도, 세션을 다시 저장할지 여부를 결정합니다. 대부분의 경우 `false`로 설정합니다.
rolling: true, // 요청이 있을 때마다 세션 쿠키의 만료 시간을 리셋할지 여부를 결정합니다.
saveUninitialized: true, // 초기화되지 않은 세션들을 저장할 지 여부를 결정합니다.
cookie: {
secure: true, // 실제 운영모드에서는 true를 사용해야함. 쿠키 설정은 쿠키가 HTTPS를 통해서만 전송되도록 합니다.
httpOnly: true, // 옵션은 JavaScript를 통한 쿠키 접근을 방지합니다.
maxAge: 1800000, // 쿠키의 만료 시간을 설정
},
})
);
-
secret
: 세션을 암호화하기 위한 비밀키입니다. 보안을 위해 복잡하고 예측 불가능한 문자열을 사용해야 합니다. -
name
: 클라이언트의 브라우저에 저장되는 쿠키의 이름을 설정합니다. 기본값은 'connect.sid'입니다. -
resave
: 옵션은 세션 데이터가 변경되지 않았더라도, 세션을 다시 저장할지 여부를 결정합니다대부분의 경우false
로 설정합니다. -
rolling
: 요청이 있을 때마다 세션 쿠키의 만료 시간을 리셋할지 여부를 결정합니다. -
saveUninitialized
: 초기화되지 않은 세션들을 저장할 지 여부를 결정합니다.true
: 모든 세션, 즉 사용자가 아직 인증되지 않은 세션도 저장소에 저장됩니다. 이는 세션 저장소에 많은 수의 미사용 세션을 생성할 수 있으므로 주의해야 합니다.false
: 세션에 어떤 데이터도 설정되지 않으면 세션 저장소에 저장하지 않습니다. 이는 저장소의 부담을 줄이는 데 도움이 됩니다.
-
proxy
: 프록시 서버를 통한 연결을 신뢰할지 여부를 결정합니다. 이는 주로secure
쿠키 옵션과 관련이 있습니다.true
: Express가 프록시 서버 뒤에 배치된 경우 (예: Heroku, AWS ELB)에 유용합니다.X-Forwarded-Proto
헤더를 신뢰하여 HTTPS 연결을 확인합니다.false
: 프록시 서버를 통한 연결을 신뢰하지 않습니다. 프록시 서버를 사용하지 않는 경우 적합합니다.
-
cookie.secure
: 쿠키가 HTTPS를 통해서만 전송되도록 합니다. 운영에서는true
를 사용해야만 하며false
로 하면 HTTP 연결에서도 쿠키가 전송될 수 있습니다. -
cookie.httpOnly
: JavaScript를 통한 쿠키 접근을 방지합니다. 이는 XSS(Cross-Site Scripting) 공격으로부터 쿠키를 보호하는 데 도움이 됩니다.true
: 클라이언트 측 스크립트가 쿠키에 접근할 수 없습니다. 보안을 위해 권장됩니다.
-
cookie.maxAge
: 쿠키의 만료 시간 설정
cookie-parser
cookie-parser
는 Express 애플리케이션에서 HTTP 쿠키를 파싱하고 쉽게 관리할 수 있게 해주는 미들웨어입니다. 쿠키는 클라이언트의 브라우저에 저장되는 작은 데이터 조각으로, 사용자 세션 관리, 개인화된 설정 유지, 추적 등 다양한 용도로 사용됩니다. cookie-parser
는 이러한 쿠키를 서버에서 더 효과적으로 다루기 위한 도구입니다.
설치
yarn add cookie-parser
const express = require('express');
const cookieParser = require('cookie-parser');
const app = express();
app.use(cookieParser());
쿠키 설정하기
res.cookie()
함수를 사용하여 쿠키를 설정할 수 있습니다.
app.get('/set-cookie', (req, res) => {
res.cookie('username', 'John Doe', { maxAge: 900000, httpOnly: true });
res.send('Cookie has been set');
});
쿠키 읽기
req.cookies
객체를 사용하여 요청에서 쿠키를 읽을 수 있습니다.
app.get('/get-cookie', (req, res) => {
const username = req.cookies.username;
res.send(`Hello, ${username}`);
});
쿠키 삭제하기
res.clearCookie()
함수를 사용하여 쿠키를 삭제할 수 있습니다.
app.get('/clear-cookie', (req, res) => {
res.clearCookie('username');
res.send('Cookie has been cleared');
});
보안 및 옵션
cookie-parser
를 사용할 때, 쿠키의 보안 옵션을 적절히 설정하는 것이 중요합니다. 예를 들어, httpOnly
옵션을 true
로 설정하면 클라이언트 측 스크립트가 쿠키에 접근하는 것을 방지하여 XSS 공격을 막을 수 있습니다. 또한, secure
옵션을 사용하여 HTTPS를 통해서만 쿠키를 전송하도록 설정할 수도 있습니다.
cors
CORS는 웹 페이지가 다른 출처의 리소스에 접근할 수 있도록 허용하는 메커니즘입니다. 기본적으로 웹 브라우저는 '동일 출처 정책(Same-Origin Policy)'을 적용하여, 다른 출처의 리소스에 대한 요청을 제한합니다. 이는 보안상의 이유로 중요하지만, 현대 웹 애플리케이션에서는 종종 다른 출처의 API나 리소스에 접근해야 할 필요가 있습니다. CORS는 이러한 상황에서 안전한 방법으로 리소스를 공유할 수 있는 규칙을 제공합니다.
설치
yarn add cors
사용
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors());
origin
하나 또는 여러 출처를 지정하여 요청을 허용할 수 있습니다.
origin
옵션에 true
를 설정하는 경우, 서버는 모든 출처의 요청을 허용하지만, Access-Control-Allow-Origin
헤더에 요청을 보낸 출처를 동적으로 설정합니다. 이는 서버가 다양한 출처에서 오는 요청을 허용하면서도, 각각의 출처를 명시적으로 인식하고자 할 때 유용합니다.
app.use(
cors({
origin: true,
}),
);
app.use(
cors({
origin: 'https://example.com',
}),
);
methods
GET
, POST
등 특정 HTTP 메소드에 대한 요청만 허용하도록 설정할 수 있습니다.
app.use(
cors({
methods: ['GET', 'POST'],
}),
);
allowHeaders
클라이언트가 요청에 포함할 수 있는 추가 헤더를 지정할 수 있습니다.
app.use(
cors({
allowedHeaders: ['Content-Type', 'Authorization'],
}),
);
credentials
인증 정보(쿠키, HTTP 인증 및 클라이언트 SSL 인증)와 같은 사용자 자격 증명을 포함한 요청을 허용할 수 있습니다.
app.use(
cors({
credentials: true,
}),
);
preflightContinue
CORS의 사전 요청(Pre-flight Request) 처리 방식을 결정합니다. 사전 요청은 특정한 종류의 요청(예: PUT
, DELETE
또는 사용자 정의 헤더를 포함하는 요청)을 보내기 전에 브라우저가 서버의 허용 여부를 미리 확인하는 것입니다.
true
: CORS 미들웨어가 사전 요청을 처리한 후, 다음 미들웨어로 요청을 전달합니다.false
(기본값): CORS 미들웨어가 사전 요청을 완전히 처리하고 클라이언트에 응답합니다.
app.use(
cors({
preflightContinue: false,
}),
);
optionsSuccessStatus
옵션은 사전 요청에 대한 응답으로 반환되는 HTTP 상태 코드를 설정합니다. 기본값은 204
이며, 이는 'No Content'를 의미합니다. 일부 레거시 브라우저는 204
대신 다른 상태 코드를 기대할 수 있으므로, 이를 변경할 필요가 있을 수 있습니다.
app.use(
cors({
optionsSuccessStatus: 204, // 일부 레거시 브라우저는 200 상태 코드를 기대함
}),
);
사용예시
app.use(
cors({
origin: "http://localhost:3000",
credentials: true,
preflightContinue: false,
optionsSuccessStatus: 204,
})
);```
nodemon
소스 파일이 변경될 때마다 자동으로 Node.js 애플리케이션을 재시작해주는 기능을 가지고 있습니다.
설치
yarn add -D nodemon
//package.json
{
"scripts": {
"dev": "nodemon app.js"
}
}
특정 파일 감시
Nodemon은 기본적으로 JavaScript 파일을 감시합니다. 하지만 --watch
옵션을 사용하여 특정 파일이나 디렉토리를 지정할 수 있습니다.
nodemon --watch app.js --watch lib/ app.js
감시 제외 파일 설정
--ignore
옵션을 사용하여 Nodemon이 특정 파일이나 디렉토리의 변경을 무시하도록 설정할 수 있습니다.
nodemon --ignore test/ app.js
환경 변수 사용
Nodemon은 .env
파일에서 환경 변수를 읽을 수도 있습니다.
nodemon -r dotenv/config app.js