๐Ÿ”ฅTIL #6. ๋ชจ๋“ˆํ™”์™€ MVC ํŒจํ„ด #2

๋ฐฑ์Šน์ง„ยท2021๋…„ 1์›” 1์ผ
0

NodeJS

๋ชฉ๋ก ๋ณด๊ธฐ
7/7

์ง€๋‚œ ํฌ์ŠคํŒ…์— ์ด์–ด ์ด๋ฒˆ์—๋Š” project์—์„œ ๋ชจ๋“ˆํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋‹ค๋ฃฌ๋‹ค. ์•ž์—์„œ ๋‹ค๋ฃจ์—ˆ๋˜ ๋ชจ๋“ˆ์„ ๋‹ค์‹œ ๋ณด์ž.

  1. server.js
  2. app.js
  3. Router
  4. Controller
  5. Service
  6. Model

์œ„์—์„œ ๋ถ€ํ„ฐ ์•„๋ž˜๋ฐฉํ–ฅ์œผ๋กœ Database์— ๊ฐ€๊นŒ์›Œ์ง€๋ฉด ๊ฐ layer๋Š” ์•„๋ž˜ layer๋งŒ ์˜์กดํ•œ๋‹ค.

node.js ์‹œ๋ฆฌ์ฆˆ์˜ ์•ž๋ถ€๋ถ„์—์„œ ์ง„ํ–‰ํ•œ project(์‚ฌ์šฉ์ž์™€ ํฌ์ŠคํŒ…)๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋ชจ๋“ˆํ™”๋ฅผ ์ ์šฉํ•ด ๋ณด์ž.

server.js

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๋ฅผ ์˜์กดํ•˜์ง€๋งŒ ๊ทธ ์™ธ ์šฉ๋„๋กœ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.


app.js

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) ์ถ”๊ฐ€

Routes

index.js

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 ๋“ค์„ ์˜์กดํ•œ๋‹ค.

userRouter.js

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 ๋ฅผ ์˜์กด.


Controllers

index.js

const UserController = require('./UserController')

module.exports = {
  UserController,
}

Routes/index.js์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Routes๊ฐ€ Controller๋ฅผ ์˜์กดํ•˜๋Š” ์ž…๊ตฌ์™€ ๊ฐ™์€ ์—ญํ• ์ด๋‹ค.

userController.js

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๋ฅผ ์ œ์™ธํ•œ ๋ชจ๋“  ์ฒ˜๋ฆฌ๋ฅผ ๋‹ด๋‹น.


Services

index.js

const UserService = require('./UserService')

module.exports = {
  UserService,
}

ํƒ€ module index.js์™€ ์‚ฌ์šฉ์˜๋„ ๋™์ผ.

userService.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 ๋ฅผ ๋‹ด๋‹นํ•œ๋‹ค.


prisma(= Model)

index.js

const { PrismaClient } = require('@prisma/client')
const prisma = new PrismaClient()

module.exports = prisma 
// ์ด๋ ‡๊ฒŒ ์ธ์Šคํ„ด์Šคํ™” ๋œ prisma ๋Š” Service ๋ ˆ์ด์–ด์—์„œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ ‘๊ทผํ•˜๋Š” ๋กœ์ง์— ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
profile
12๋…„ .NET ๊ฐœ๋ฐœ ๊ฒฝ๋ ฅ์„ ๊ฐ€์ง„ ์›น ์ดˆ์งœ ๊ฐœ๋ฐœ์ž์ž…๋‹ˆ๋‹ค :)

0๊ฐœ์˜ ๋Œ“๊ธ€