์ง๋ ํฌ์คํ ์ ์ด์ด ์ด๋ฒ์๋ project์์ ๋ชจ๋ํํ๋ ๋ฐฉ๋ฒ์ ๋ค๋ฃฌ๋ค. ์์์ ๋ค๋ฃจ์๋ ๋ชจ๋์ ๋ค์ ๋ณด์.
- server.js
- app.js
- Router
- Controller
- Service
- Model
์์์ ๋ถํฐ ์๋๋ฐฉํฅ์ผ๋ก Database์ ๊ฐ๊น์์ง๋ฉด ๊ฐ layer๋ ์๋ layer๋ง ์์กดํ๋ค.
node.js ์๋ฆฌ์ฆ์ ์๋ถ๋ถ์์ ์งํํ project(์ฌ์ฉ์์ ํฌ์คํ )๋ฅผ ๊ธฐ์ค์ผ๋ก ๋ชจ๋ํ๋ฅผ ์ ์ฉํด ๋ณด์.
require('dotenv').config() const { PORT } = process.env const http = require('http') const app = require('./app') const server = http.createServer(app) // Server ๋ express ์ฑ์ ์์กด์ฑ์ ๊ฐ์ง๋๋ค. const prisma = require('./prisma') const start = async () => { try { server.listen(PORT, () => console.log(`Server is listening on ${PORT}`)) } catch (err) { console.error(err) await prisma.$disconnect() } }
server.js ๋ app.js๋ก๋ถํฐ express app์ ๊ฐ์ ธ์ server๋ฅผ ์คํํ๋ค. prisma๋ server ์ข ๋ฃ์ disconnect ์ฒ๋ฆฌ๋ฅผ ํด์ผ ํ๊ธฐ์ model layer๋ฅผ ์์กดํ์ง๋ง ๊ทธ ์ธ ์ฉ๋๋ก ์ฌ์ฉํ์ง ์๋๋ค.
const express = require('express') const routes = require('./routes') const logger = require('morgan')('dev') const app = express() app.use(express.json()) app.use(logger) app.use(routes) // Route ์ ์์กด์ฑ์ ๊ฐ์ง๋๋ค. app.use((err, req, res, next) => { const { status, message } = err console.error(err) res.status(status || 500).json({ message }) }) module.exports = app
app.js ๋ Route layer๋ฅผ ์์กดํ๋ฉฐ ๋ค์ ๊ธฐ๋ฅ์ ๋ด๋นํ๋ค.
- Express app ์์ฑ
- app ์ฌ์ฉ์ ํ์์ ์ธ middleware(json parser, logger, route, error) ์ถ๊ฐ
const express = require('express') const router = express.Router() // express ๋ผ์ฐํ ๊ธฐ๋ฅ์ ์ฌ์ฉํ๊ธฐ ์ํด์ router ๊ฐ์ฒด๊ฐ ํ์ํฉ๋๋ค. const UserRouter = require('./UserRouter') router.use('/users', UserRouter) // '/users' ์๋ํฌ์ธํธ๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํด UserRouter ๋ฅผ ๋ถ์ฌ์ค๋๋ค. module.exports = router // ์ด๋ ๊ฒ ๋ด๋ณด๋ธ router ๋ express app ์ ๋ฏธ๋ค์จ์ด๋ก ์ฌ์ฉ๋ฉ๋๋ค.
Routes์๋ user, article ๊ด๋ จ route๊ฐ ์์ฑ๋ ๊ฒ์ด๋ค. app.js ์ ์ฅ์์ ํ๋ฒ์ require๋ก Routes ์ ๋ณด๋ฅผ ์ป์ด์ผ simple ํ๋ฏ๋ก ์ด๋ฅผ ์ํด index.js๋ฅผ app.js๊ฐ ์์กดํ ๋์์ผ๋ก ๋ง๋ ๋ค. index.js๋ express.Router ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด ์ ๊ณตํ๋ฉฐ ์ด router๋ ๊ฐ์ Routes ํด๋์ ์๋ route ๋ค์ ์์กดํ๋ค.
const express = require('express') const router = express.Router() const { UserController } = require('../controllers') // Route ๋ ์ค์ง Controller ์๋ง ์์กด ํฉ๋๋ค. router.post('/login', UserController.logIn) // '/users/login' ํธ๋ค๋ง ํ๋ ์ปจํธ๋กค๋ฌ ํจ์ router.post('/signup', UserController.signUp) // '/users/signUp' ํธ๋ค๋ง ํ๋ ์ปจํธ๋กค๋ฌ ํจ์ module.exports = router // ์ด๋ ๊ฒ ๋ด๋ณด๋ด๋ฉด ๋ถ๋ชจ router ์ ์๋์ผ๋ก ์ฐ๊ฒฐ๋ฉ๋๋ค.
user์ ๊ด๋ จ๋ request ์ฒ๋ฆฌ ๋ก์ง์ ๊ด๋ฆฌํ๋ค. router ๋ฅผ ๋ง๋ค์ด ์ธ๋ถ์ ์ธ api ๋ฐ ์์ฒญ ์ฒ๋ฆฌ๋ฅผ ์ฃผ์ ํ๊ณ ์ด๋ฅผ index.js๊ฐ ์ฌ์ฉํ ์ ์๋๋ก exports ํ๋ค.
์์ฒญ ์ฒ๋ฆฌ๋ Controller layer๊ฐ ๋ด๋นํ๋ฉฐ userRouter๋ userController ๋ฅผ ์์กด.
const UserController = require('./UserController') module.exports = { UserController, }
Routes/index.js์ ๋ง์ฐฌ๊ฐ์ง๋ก Routes๊ฐ Controller๋ฅผ ์์กดํ๋ ์ ๊ตฌ์ ๊ฐ์ ์ญํ ์ด๋ค.
const { AUTH_TOKEN_SALT } = process.env const bcrypt = require('bcrypt') const jwt = require('jsonwebtoken') // Controller ๋ ์ค์ง Service ๋ ์ด์ด์๋ง ์์กดํฉ๋๋ค. const { UserService } = require('../services') // ์์ฃผ ์ฌ์ฉ๋๋ ๋ก์ง์ utils ๋ก ๋นผ์ ๋ชจ๋๋ก ๊ด๋ฆฌํฉ๋๋ค. const { errorGenerator } = require('../utils') // ์๋ ์ ์๋ ํจ์๋ ์ง๋ ์์ ์๊ฐ์ ๋ค๋ฃฌ ๋ด์ฉ ์ ๋๋ค. const signUp = async (req, res, next) => { try { const { email, password } = req.body const foundUser = await UserService.findUser({ email }) if (foundUser) errorGenerator({ statusCode: 409, message: 'duplicated' }) const hashedPassword = await bcrypt.hash(password, 10) const createdUser = await UserService.createUser({ email, password: hashedPassword, }) res.status(201).json({ message: 'user created', user_id: createdUser.id, }) } catch (err) { next(err) } } const logIn = async (req, res, next) => { try { const { email, password: inputPassword } = req.body const foundUser = await UserService.findUser({ email }) if (!foundUser) errorGenerator({ statusCode: 400, message: 'client input invalid' }) const { id, password: hashedPassword } = foundUser const isValidPassword = await bcrypt.compare(inputPassword, hashedPassword) if (!isValidPassword) errorGenerator({ statusCode: 400, message: 'client input invalid' }) const token = jwt.sign({ id }, AUTH_TOKEN_SALT, { expiresIn: '1h' }) res.status(200).json({ message: 'login success!', token }) } catch (err) { next(err) } } module.exports = { logIn, signUp, }
Controller๋ request์ ๋ํ response ๋ฅผ ๋ด๋นํ๋ค. Model ์ ์ด ๊ถํ์ ๊ฐ๋ Service๋ฅผ ์์กดํ๋ฉฐ Service๋ฅผ ํตํ Database CRUD๋ฅผ ์ ์ธํ ๋ชจ๋ ์ฒ๋ฆฌ๋ฅผ ๋ด๋น.
const UserService = require('./UserService') module.exports = { UserService, }
ํ module index.js์ ์ฌ์ฉ์๋ ๋์ผ.
const prisma = require('../prisma') // Service ๋ก์ง์ ์ค์ง Model(=Prisma) ์๋ง ์์กดํฉ๋๋ค. const { makeDataForCreate } = require('../utils') const createUser = (fields) => { const data = makeDataForCreate(fields) return prisma.users.create({ data }) } const findUser = (field) => { const [uniqueKey] = Object.keys(field) const isKeyId = uniqueKey === 'id' const value = isKeyId ? Number(field[uniqueKey]) : field[uniqueKey] return prisma.users.findOne({ where: { [uniqueKey]: value } }) } module.exports = { createUser, findUser, }
Database์ ๋ํ ์ ์ด๋ฅผ ํ๋ฏ๋ก prisma๋ฅผ ์์กดํ๋ค. database์ ๋ํ CRUD ๋ฅผ ๋ด๋นํ๋ค.
const { PrismaClient } = require('@prisma/client') const prisma = new PrismaClient() module.exports = prisma // ์ด๋ ๊ฒ ์ธ์คํด์คํ ๋ prisma ๋ Service ๋ ์ด์ด์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ๊ทผํ๋ ๋ก์ง์ ์ฌ์ฉ๋ฉ๋๋ค.