1 λΆ„ μ†Œμš”

Layered Patternμ΄λž€ πŸ™€

λ°±μ—”λ“œ APIλ₯Ό κ΅¬ν˜„ν• λ•Œ 널리 μ“°μ΄λŠ” νŒ¨ν„΄μ€‘ λ ˆμ΄μ–΄λ“œ μ•„ν‚€ν…μ²˜(Layered achitecture) νŒ¨ν„΄μ΄ μžˆλ‹€. λ ˆμ΄μ–΄λ“œ μ•„ν‚€ν…μ³λ‘œ APIλ₯Ό κ΅¬ν˜„ν• λ•ŒλŠ” 역할에 따라 λ…λ¦½λœ λͺ¨λ“ˆλ‘œ λ‚˜λˆ„μ–΄μ„œ μ½”λ“œλ₯Ό κ΅¬ν˜„ν•œλ‹€.
layered-1

Route, Controller, Service, Model 각각의 λ ˆμ΄μ–΄κ°€ ν•˜λ‚˜μ˜ ν΄λ”μ΄μž 역할을 μ˜λ―Έν•œλ‹€.

  1. 큰 λ°•μŠ€μ—μ„œ μž‘μ€ λ°•μŠ€λ‘œ 갈 수둝 더 데이터λ₯Ό λ‹€λ£¨λŠ” 둜직(λ°μ΄ν„°λ² μ΄μŠ€ μ ‘κ·Όν•˜λŠ” 둜직)에 κ·Όμ ‘ν•˜κ²Œ λœλ‹€.
  2. λ˜ν•œ, 각각의 λ ˆμ΄μ–΄λŠ” μ˜€λ‘œμ§€ λ°”λ‘œ μ•„λž˜μ— μžˆλŠ” λ ˆμ΄μ–΄μ—λ§Œ μ˜μ‘΄ν•˜κ²Œ λœλ‹€.
    • Route β†’ Controller
    • Controller β†’ Service
    • Service β†’ Model

예λ₯Όλ“€μ–΄, Route λŠ” Service λ‘œμ§μ„ μ „ν˜€ λͺ¨λ₯΄κ³  μ•„μ˜ˆ κ΄€μ—¬ μ‘°μ°¨ ν•˜μ§€ μ•ŠλŠ”λ‹€. λ”°λΌμ„œ, Service λ‘œμ§μ„ 변경해도 Route 와 Controller 의 μ½”λ“œλŠ” λ°”λ€” ν•„μš”κ°€ μ—†λ‹€.

즉 λ‹€μŒκ³Ό 같은 μƒν™©μ—μ„œ μœ μ—°ν•˜κ²Œ λŒ€μ²˜ν•  수 μžˆλ‹€λŠ” μ˜λ―Έμ΄λ‹€.

λ•Œλ•Œλ‘œ, μ„œλΉ„μŠ€λ₯Ό κ΅¬ν˜„ν•˜λ‹€κ°€ RDBMS(κ΄€κ³„ν˜• 데이터 베이슀) β†’ NoSQL(ex. mongoDB) 둜 μ΄μ „ν•˜λŠ” κ²½μš°κ°€ μžˆλŠ”λ°, Route와 Controller 의 λ‘œμ§μ€ μ „ν˜€ λ°”λ€Œμ§€ μ•Šμ€μ±„λ‘œ 데이터λ₯Ό λ‹€λ£¨λŠ” Service 와 Model 의 둜직만 λ³€κ²½ ν•΄ μ£Όλ©΄ λœλ‹€.

μ‹€μŠ΅

model

import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

const productDetail = async productId => {
  const detail = await prisma.$queryRaw`
    SELECT
      products.id,
      eng_name,
      price,
      is_new,
      is_main,
      quantity,
      sale_rate,
      categories.name as cate_name,
      subcategories.name as subcate_name,
      url,
      images.id as image_id
    FROM
      products
    JOIN
      categories on category_id = categories.id
    JOIN
      images on products.id = images.product_id
    JOIN
      subcategories on subcategories.id = subcategory_id
    WHERE
      products.id = ${productId};
  `;

  return detail;
};

export default { productDetail };

service


import { productDetailDao } from '../models';

const productDetail = async productId => {
  const detail = await productDetailDao.productDetail(productId);

  const tmp = detail[0];

  tmp.url = detail.map((e, i) => {
    return { id: detail[i]['image_id'], image: detail[i].url };
  });

  return detail[0];
};

export default { productDetail };

controller

import { productDetailServices } from '../services';

const productDetail = async (req, res) => {
  try {
    const { productId } = req.params;

    const detail = await productDetailServices.productDetail(productId);

    res.status(200).send(detail);
  } catch (err) {
    console.log(err);
    res.status(500).send(err);
  }
};

export default { productDetail };

μ²˜μŒμ—λŠ” 이런 λͺ¨λ“ˆν™”λ₯Ό μ™œν•˜λŠ”μ§€ 이해가 λ˜μ§€μ•Šμ•˜λŠ”λ°

ν˜‘μ—…μ„ ν•˜λŠ”κ³Όμ •μ—μ„œ 이 과정이 μ™œ ν•„μš”ν•œκ°€λ₯Ό μ•„μ£Ό 깊이 κΉ¨λ‹¬μ•˜λ‹€.

λ§Œμ•½ λͺ¨λ“ˆν™”λ₯Ό ν•˜μ§€μ•Šμ•˜λ‹€λ©΄ νŒ€μ›λ“€μ΄ μž‘μ„±ν•œ μ½”λ“œλ₯Ό λΆ„μ„ν•˜λŠ”λ° μžˆμ–΄μ„œ μƒλ‹Ήν•œ μ‹œκ°„μ΄ 걸렸을것이닀.

λ‹€ν–‰νžˆ layered pattern을 μ‚¬μš©ν•˜λ‹ˆ νŒ€μ›λ“€μ΄ 무엇을 μƒκ°ν•˜λ©° μ½”λ“œλ₯Ό 짜고

μ–΄λ–€ APIλ₯Ό λ§Œλ“€μ—ˆλŠ”μ§€ ν•œλˆˆμ— μ•Œμˆ˜μžˆμ—ˆκ³ 

μˆ˜μ • λ˜ν•œ μ–΄λŠλΆ€λΆ„μ„ μˆ˜μ •ν•΄μ•Όν•˜λŠ”μ§€ λ°”λ‘œ μ•Œμˆ˜μžˆμ—ˆλ‹€.

μ—…λ°μ΄νŠΈ: