Express 사용 안하고 API 서버 만들어보기
2020-12-06 21:54:02

페북 그룹에서 Express를 사용 하지 않고 API 서버 만드는 글을 보고 나도 도전 해보았다.

DB 연결은 안 하고 기타 라이브러리 없이 기본적인 구조 및 라우팅만 만들어 보기로 했다.

구조는 아래와 같이 작성 하였다.

1
2
3
4
5
6
7
8
9
├── app
│ ├── controllers
├── user.js
├── lib
├── routes.js
├── utils.js
├── package.json
├── node_modules
├── server.js

파라미터 받기

Express에서는 쿼리스트링은 req.query로 받고 POST의 경우에는 body-parser를 설치하여

사용 했었는데 이번엔 직접 utils.js에 파라미터 처리 함수를 작성 해보았다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
const url = require('url');

const NONE_CHECK_PARAM_GET_URL = [
'/userAll'
];

/**
* GET, POST 파라미터 파싱
* @param {*} req
*/
const parseParameters = (req) => {
return new Promise((resolve, reject) => {
if (req.method === "GET") { // GET일 경우 처리
const qs = url.parse(req.url, true).query;
if (NONE_CHECK_PARAM_GET_URL.indexOf(req.url) < 0 && Object.keys(qs).length === 0) return reject(new Error('파라미터가 안 넙어 왔습니다'));
req.body = qs;
return resolve();
} // 이외 POST 처리
const body = [];
req
.on("error", (err) => reject(err))
.on("data", (chuck) => body.push(chuck))
.on("end", () => {
try {
req.body = JSON.parse(Buffer.concat(body).toString());
resolve();
} catch(e) {
if (body.length == 0) e.message = '파라미터가 안 넘어 왔습니다.';
reject(e);
}
});
});
};

METHOD의 따라 GET인 경우 내장된 URL 모듈을 이용해 쿼리스트링 데이터를 넘겼으며

POST의 경우에는 공식 문서 가이드에 따라 해봤는데 잘 넘어오는 걸 확인 할 수 있었다.

데이터 모델 작성 하기

DB를 안 쓰기로 했으므로 간단하게 글로벌 변수에 넣거나 가져오는 걸로 처리를 했다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
const create = (id, data) => { // 생성
return new Promise((resolve, reject) => {
if (global.user[id]) return reject(new Error('이미 존재하는 아이디'));
global.user[id] = data;
return resolve(global.user[id]);
});
};

const findByOne = (id) => { // 하나 가져오기
return new Promise((resolve, reject) => {
if (!global.user[id]) return reject(new Error('존재하지 않은 회원'));
return resolve(global.user[id]);
});
}

const findAll = () => { // 전체 가져오기
return new Promise((resolve, reject) => {
return resolve(global.user);
});
};

module.exports = {
create,
findByOne,
findAll,
};

컨트롤러 작성 하기

데이터 모델을 호출 하기 위한 컨트롤러를 만들어 본다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

const userModel = require('../models/user');

const createUser = async (req) => {
try {
return await userModel.create(req.body.id, req.body);
} catch (e) {
throw e;
}
};

const getUserByID = async (req) => {
try {
return await userModel.findByOne(req.body.id);
} catch (e) {
throw e;
}
};

const getAllUser = async (req) => {
try {
return await userModel.findAll();
} catch (e) {
throw e;
}
};

module.exports = {
createUser,
getUserByID,
getAllUser,
};

라우터 작성

Express로 작성할 때 보통 따로 만들지는 않았었는데 걍 문득 레일즈였나..? 생각 나서 따로 분류를 해보았다.

1
2
3
4
5
6
7
8
9
10
11
12
13
const user = require('../app/controllers/user');

const router = {
POST: {
'/userCreate': user.createUser,
},
GET: {
'/userByID': user.getUserByID,
'/userAll': user.getAllUser,
}
};

module.exports = router;

공통 응답 처리 작성

일일이 res 하기 귀찮으므로 공통으로 만들어서 호출을 하자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* 공통) 응답 처리
* @param {*} err
* @param {*} body
* @param {*} res
*/
const responseResult = (err, body, res) => {
const results = {
status: 200,
message: 'SUCCESS',
body,
};
if (err) {
results.status = 500;
results.message = err.message;
} else if (!results.message && typeof results.message === "object") {
results.status = 403;
results.message = "페이지를 찾을 수 없습니다.";
}
res.writeHead(results.status, { "Content-Type": "application/json" });
res.end(JSON.stringify(results));
};

exports.parseParameters = parseParameters;
exports.responseResult = responseResult;

Server.js 작성

이제 재료를 모두 만들었으니 실제 구동 부분을 내장 http 모듈을 이용하여 만들어 본다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
const http = require("http");

const utils = require('./libs/utils');
const router = require('./libs/routes');

const PORT = process.env.PORT || 3000;

const server = http.createServer(async (req, res) => {
const opt = {
err: null,
body: null,
res,
};
try {
await utils.parseParameters(req);
} catch (e) {
return utils.responseResult(e, opt.body, opt.res);
}
let url = req.url;
if (req.method === 'GET') url = req.url.split('?')[0];
try {
opt.body = await router[req.method][url].call(null, req);
} catch (e) {
if (router[req.method][url]) opt.err = e;
}
utils.responseResult(opt.err, opt.body, opt.res);
});

server.listen(PORT, () => {
global.user = {};
console.log(`서버는 ${PORT}에서 동작중..`);
});

검색 좀 해보면서 만들어보니 음 생각보다 어렵지 않았고 막상 설명 적을 것도 없다… 😰

다만 이번에 만들다가 안 건데 미들웨어 처리가 Node.js 내장이 아니고 Express 내장이였다.

검색 해보니 직접 구현 관련 글들 좀 나오던데 굳이 따라해보고 싶진 않았음..

Express는 가볍고 쓰기 쉬운 프레임워크 라고 생각하기 때문에 굳이 안 쓰고 순수하게

짤 필요성을 못 느껴서 앞으로도 Node.js 기반으로 개발 할 때는 계속 쓸 거 같다 😊

참조

Prev
2020-12-06 21:54:02
Next