0. 목표 API
예 :
나는 사용자 정보 조회 API를 만들어보겠다.
구조 :
.env :
DB_HOST=localhost
DB_PORT=3306
DB_USER=root
DB_PASSWORD =
DB_NAME =
DB_TABLE =
PORT = 3000
NODE_ENV = development # production - 배포 모드, development - 개발 모드
1. 관련 모듈 설치
나는 미리 내게 필요한 모듈을 다 설치해두겠다.
node -v
npm -v
npm init
npm install -g yarn
yarn -v
npm install express --save
yarn add express
npm install --save-dev @babel/core @babel/cli @babel/preset-env @babel/node
yarn add @babel/core @babel/cli @babel/preset-env @babel/node --dev
npm install --save-dev nodemon
yarn add nodemon --dev
npm i http-status-codes --save
yarn add http-status-codes --save
yarn add swagger-jsdoc swagger-ui-express swagger-cli --save-dev
npm i swagger-jsdoc swagger-ui-express swagger-cli --save-dev
npm install mysql2
npm install dotenv
npm install cors
npm install express-async-handler
2. package.json 세팅
마찬가지로 미리 세팅해두겠다.
{
"name": "umc_node",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "nodemon --exec babel-node index.js"
},
"author": "",
"type": "module",
"license": "ISC",
"dependencies": {
"cors": "^2.8.5",
"dotenv": "^16.4.5",
"express": "^4.19.2",
"http-status-codes": "^2.3.0",
"mysql2": "^3.11.0",
"swagger-cli": "^4.0.4",
"swagger-jsdoc": "^6.2.8",
"swagger-ui-express": "^5.0.1"
},
"devDependencies": {
"@babel/cli": "^7.25.6",
"@babel/core": "^7.25.2",
"@babel/node": "^7.25.0",
"@babel/preset-env": "^7.25.4",
"nodemon": "^3.1.4"
}
}
3. index.js 기본 세팅
import express from 'express';
import { specs } from './config/swagger.config.js';
import SwaggerUi from 'swagger-ui-express';
import dotenv from 'dotenv';
import cors from 'cors';
import { response } from './config/response.js';
import { BaseError } from './config/error.js';
import { status } from './config/response.status.js';
dotenv.config();
const app = express();
app.set('port', process.env.PORT || 3000)
app.use(cors());
app.use(express.static('public'));
app.use(express.json());
app.use(express.urlencoded({extended: false}));
app.use('/api-docs', SwaggerUi.serve, SwaggerUi.setup(specs));
app.use((req, res, next) => {
const err = new BaseError(status.NOT_FOUND);
next(err);
});
app.use((err, req, res, next) => {
console.log(err);
res.locals.message = err.message;
res.locals.error = process.env.NODE_ENV !== 'production' ? err : {};
res.status(err.data.status).send(response(err.data));
});
app.listen(app.get('port'), () => {
console.log(`Example app listening on port ${app.get('port')}`);
});
4. config 폴더 내부
db.connect.js
import mysql from 'mysql2/promise';
import dotenv from 'dotenv';
dotenv.config();
export const pool = mysql.createPool({
host: process.env.DB_HOST,
user: process.env.DB_USER,
port: process.env.DB_PORT,
database: process.env.DB_TABLE,
password: process.env.DB_PASSWORD,
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0,
connectTimeout: 60000
});
error.js
export class BaseError extends Error {
constructor(data){
super(data.message);
this.data = data;
}
}
response.js
export const response = ({isSuccess, code, message}, result) => {
return {
isSuccess: isSuccess,
code: code,
message: message,
result: result
}
};
response.status.js
import { StatusCodes } from "http-status-codes";
export const status = {
// success
SUCCESS: {status: StatusCodes.OK, "isSuccess": true, "code": 2000, "message": "success!"},
// error
// common err
INTERNAL_SERVER_ERROR: {status: StatusCodes.INTERNAL_SERVER_ERROR, "isSuccess": false, "code": "COMMON000", "message": "서버 에러, 관리자에게 문의 바랍니다." },
BAD_REQUEST: {status: StatusCodes.BAD_REQUEST, "isSuccess": false, "code": "COMMON001", "message": "잘못된 요청입니다." },
UNAUTHORIZED: {status: StatusCodes.UNAUTHORIZED, "isSuccess": false, "code": "COMMON002", "message": "권한이 잘못되었습니다." },
METHOD_NOT_ALLOWED: {status: StatusCodes.METHOD_NOT_ALLOWED, "isSuccess": false, "code": "COMMON003", "message": "지원하지 않는 Http Method 입니다." },
FORBIDDEN: {status: StatusCodes.FORBIDDEN, "isSuccess": false, "code": "COMMON004", "message": "금지된 요청입니다." },
NOT_FOUND: {status: StatusCodes.NOT_FOUND, "isSuccess": false, "code": "COMMON005", "message": "요청한 페이지를 찾을 수 없습니다. 관리자에게 문의 바랍니다." },
// db error
PARAMETER_IS_WRONG: {status: StatusCodes.BAD_REQUEST, "isSuccess": false, "code": "DATABASE4001", "message": "쿼리 실행 시 전달되는 파라미터가 잘못되었습니다. 파라미터 개수 혹은 파라미터 형식을 확인해주세요."},
};
swagger.config.js
import SwaggerJsdoc from "swagger-jsdoc";
const options = {
definition: {
info: {
title: 'API',
version: '1.0.0',
description: 'API 설명'
},
host: 'localhost:3000',
basepath: '../'
},
apis: ['./src/routes/*.js', './swagger/*']
};
export const specs = SwaggerJsdoc(options);
5. src 폴더 내부
models/user.sql.js
export const getUserSql = `
SELECT *
FROM user
WHERE id = ?;
`
models/user.dao.js
import { pool } from "../../config/db.connect.js";
import { status } from "../../config/response.status.js";
import { getUserSql } from "./user.sql.js";
export const getUserDao = async (userId) => {
try {
const conn = await pool.getConnection();
const user = await pool.query(getUserSql, userId);
conn.release();
return {user: user[0]};
} catch (err) {
throw new BaseError(status.PARAMETER_IS_WRONG);
}
}
dtos/user.dto.js
export const userResponseDTO = (user) => {
return {"user": user[0]};
}
providers/user.provider.js
import { userResponseDTO } from "../dtos/user.dto.js";
import { getUserDao } from "../models/user.dao.js";
export const getUser = async (userId) => {
const {user} = await getUserDao(userId);
return userResponseDTO(user);
}
controllers/user.controller.js
import { response } from "../../config/response.js";
import { status } from "../../config/response.status.js";
import { getUser } from "../providers/user.provider.js";
export const getUserController = async (req, res, next) => {
console.log("사용자 정보 조회를 요청하였습니다!");
console.log("params:", req.params); // 값이 잘 들어오나 찍어보기 위한 테스트 용
return res.send(response(status.SUCCESS, await getUser(req.params.userId)));
}
routes/user.route.js
import express from "express";
import asyncHandler from 'express-async-handler';
import { getUserController } from "../controllers/user.controller.js";
export const userRouter = express.Router();
userRouter.get('/:userId', asyncHandler(getUserController));
6. index.js 추가 수정
import { userRouter } from './src/routes/user.route.js'
// router setting
app.use('/user', userRouter);
6. swagger 폴더 내부
user.swagger.yaml
paths:
/user/{userId}:
get:
tags:
- User
summary: 사용자 조회
parameters:
- name: userId
in: path
required: true
responses:
'200':
description: 정보 조회 성공!
schema:
type: object
properties:
status:
type: integer
example: 200
isSuccess:
type: boolean
example: true
code:
type: integer
example: 2000
message:
type: string
example: "success!"
result:
type: object
example: {
"user": {
"id": 3,
"name": "김아무개",
"age": 44
}
}
'400':
description: 잘못된 요청
schema:
type: object
properties:
status:
type: integer
example: 400
isSuccess:
type: boolean
example: false
code:
type: integer
example: COMMON001
message:
type: string
example: 쿼리 실행 시 전달되는 파라미터가 잘못되었습니다. 파라미터 개수 혹은 파라미터 형식을 확인해주세요.
7. 결과
http://localhost:3000/api-docs/
'Server > node.js' 카테고리의 다른 글
[node.js] Error calling ChatGPT API: RateLimitError: 429 You exceeded your current quota, please check your plan and billing details. (1) | 2024.10.13 |
---|---|
[node.js] The requested module 'openai' does not provide an export named 'Configuration' (0) | 2024.10.13 |
[node.js] express, restful api (0) | 2024.08.31 |
[node.js] Swagger 세팅 (0) | 2024.08.31 |
[node.js] DB 연동 (0) | 2024.08.31 |