배씨의 개발일지

3 tier architecture 본문

TIL

3 tier architecture

용찬 2023. 7. 24. 21:13

이번 주차에는 3 tier architecture에 대해 학습했다.

 

패턴 적용 중 발생한 고민 사항

  1. error 핸들링을 어느 계층에서 할 것인가?
    1-1) service, repository에서 에러 핸들링을 하고 그 에러 메시지를 controller에서 그대로 받아와서 출력해 주자!
  2. 데이터를 어떠한 방식으로 넘겨줄 것인가?
    2-2 ) 팀원 분들과 상의 후 어떤 방식으로 데이터를 쓸 건지 여쭈어본 후 인자 혹은 객체로 보내주기!

 

 

팀프로젝트 中

3 tier architecture로 작성한 코드

 

storeController.js

const StoreService = require("../service/storeService.js");

class StoreController {
  constructor() {
    this.storeService = new StoreService();
  }

  getAllStore = async (req, res, next) => {
    const getAll = await this.storeService.getAllStore();

    if (getAll.status === 400) {
      res.status(400).json({ message: getAll.errorMessage });
    } else {
      res.status(200).json({ data: getAll });
    }
  };

  getOneStore = async (req, res, next) => {
    const storeId = req.params;
    const getOne = await this.storeService.getOneStore(storeId);
    if (getOne.status === 400) {
      res.status(400).json({ message: getOne.errorMessage });
    } else {
      res.status(200).json({ data: getOne });
    }
  };

  createStore = async (req, res, next) => {
    const user = res.locals.user;
    const { name, address } = req.body;

    const create = await this.storeService.createStore(user, name, address);
    if (create.status === 400) {
      res.status(400).json({ errorMessage: create.errorMessage });
    } else {
      res.status(200).json({ Message: create.Message });
    }
  };

  updateStore = async (req, res, next) => {
    const { storeId } = req.params;
    const user = res.locals.user;
    const { name, address, password } = req.body;
    const update = await this.storeService.updateStore(
      storeId,
      user,
      name,
      address,
      password
    );
    if (update.status === 400) {
      res.status(400).json({
        errorMessage: update.errorMessage,
      });
    } else {
      res.status(200).json({ message: update.message });
    }
  };

  deleteStore = async (req, res, next) => {
    const storeId = req.params;
    const user = res.locals.user;
    const { password } = req.body;

    const deleteStore = await this.storeService.deleteStore(
      storeId,
      user,
      password
    );
    if (deleteStore.status === 400) {
      res.status(400).json({
        errorMessage: deleteStore.errorMessage,
      });
    } else {
      res.status(200).json({ message: deleteStore.message });
    }
  };
}
module.exports = StoreController;

 

 

storeService.js

const StoreRepository = require("../repository/store.repository.js");
const bcrypt = require("bcrypt");
class StoreService {
  constructor() {
    this.storeRepository = new StoreRepository();
  }
  //상점 등록
  createStore = async (user, name, address) => {
    try {
      if (!name && !address) {
        return { status: 400, errorMessage: "가게이름과 주소를 기입해야합니다." };
      }
      return await this.storeRepository.createStore(user, name, address);
    } catch (err) {
      console.log(err);
    }
  };

  //전체 지점 검색
  getAllStore = async () => {
    return await this.storeRepository.getAllStore();
  };

  //특정 지점 검색
  getOneStore = async (storeId) => {
    return await this.storeRepository.getOneStore(storeId.storeId);
  };

  //상점 정보 업데이트
  updateStore = async (storeId, user, name, address, password) => {
    const match = await bcrypt.compare(password, user.password);
    if (!match) {
      return {
        status: 400,
        errorMessage: "비밀번호가 일치하지 않습니다.",
      };
    }
    let updateValues = {};
    if (name) updateValues.name = name;
    if (address) updateValues.address = address;

    return await this.storeRepository.updateStore(
      storeId,
      user.id,
      updateValues
    );
  };

  //상점 정보 삭제
  deleteStore = async (storeId, user, password) => {
    const match = await bcrypt.compare(password, user.password);
    if (!match) {
      return { status: 400, errorMessage: "비밀번호가 일치하지 않습니다." };
    }
    return await this.storeRepository.deleteStore(storeId, user.id);
  };
}
module.exports = StoreService;

 

storeRepository.js

const Product = require("../database/model/product");
const Store = require("../database/model/store");
const User = require("../database/model/user");
const sq = require("../database/db.js").sequelize;

class StoreRepository {
  async getStoreName(storeId) {
    try {
      const store = await Store.findByPk(storeId);
      return store ? store.name : null;
    } catch (error) {
      console.error("상점 이름 조회 중 오류:", error);
      return null;
    }
  }

  async createStore(user, name, address) {
    const t = await sq.transaction();
    try {
      const existingStore = await Store.findOne({ where: { name } });

      if (existingStore) {
        return {
          status: 400,
          errorMessage: "이미 사용 중인 점포명입니다.",
        };
      }
      const store = await Store.create(
        {
          name,
          address,
          userId: user.id,
        },
        { transaction: t }
      );

      const owner = await User.findByPk(user.id, { transaction: t });

      await owner.setStore(store, { transaction: t });
      await t.commit();

      return {
        status: 200,
        Message: "점포가 등록되었습니다.",
      };
    } catch (error) {
      console.error("점포 생성 중 오류:", error);
      await t.rollback();
      return {
        status: 400,
        errorMessage: "점포 생성 중 오류가 발생했습니다.",
      };
    }
  }

  async getOneStore(storeId) {
    try {
      const store = await Store.findByPk(storeId, {
        include: {
          model: Product,
          as: "ProductList",
          attributes: ["name", "category", "price"],
        },
      });

      if (!store) {
        console.error(!store);
        return {
          status: 400,
          errorMessage: "해당 점포를 찾을 수 없습니다.",
        };
      }

      return store;
    } catch (error) {
      console.error("점포 조회 중 오류:", error);
      return {
        status: 400,
        errorMessage: "점포 조회 중 오류가 발생했습니다.",
      };
    }
  }

  async getAllStore() {
    try {
      const stores = await Store.findAll();
      return stores;
    } catch (error) {
      console.error("점포 목록 조회 중 오류:", error);
      return {
        status: 400,
        errorMessage: "점포 목록 조회 중 오류가 발생했습니다.",
      };
    }
  }

  async updateStore(storeId, id, updateValues) {
    try {
      const existingStore = await Store.findOne({
        where: { name: updateValues.name },
      });
      const store = await Store.update(updateValues, {
        where: { id: storeId, userId: id },
      });
      if (!store[0]) {
        return {
          status: 400,
          errorMessage: "해당 점포를 찾을 수 없습니다.",
        };
      }
      if (existingStore) {
        return {
          status: 400,
          errorMessage: "이미 사용 중인 점포명입니다.",
        };
      }
      return { status: 200, message: "점포가 업데이트 됐습니다." };
    } catch (error) {
      return {
        status: 400,
        errorMessage: "점포 업데이트 중 오류가 발생했습니다.",
      };
    }
  }

  async deleteStore(storeId, id) {
    try {
      const store = await Store.findOne({
        where: { id: storeId.storeId, userId: id },
      });

      if (!store) {
        return {
          status: 400,
          errorMessage: "해당 점포를 찾을 수 없습니다.",
        };
      }

      await store.destroy();

      return { message: "점포 삭제가 완료되었습니다." };
    } catch (error) {
      console.error("점포 삭제 중 오류:", error);
      return {
        status: 400,
        errorMessage: "점포 삭제 중 오류가 발생했습니다.",
      };
    }
  }
}
module.exports = StoreRepository;

'TIL' 카테고리의 다른 글

TS-미들웨어 전역 사용하기  (0) 2023.08.18
MVC 패턴  (0) 2023.08.17
VScode로 mongoDB연결  (0) 2023.06.13
오늘 알게 된 것 (Import, Export)  (0) 2023.05.31
TIL 4일 차  (0) 2023.05.19
Comments