본문 바로가기

Javascript & Typescript/실무와 가까워지는 Node.js 백엔드 개발

[4주차] 배포 및 기능 추가 코드 작성

이번 주차는 코드 배포에 관련된 내용과 추가 요구사항이 발생했을 때 대응하는 것을 학습했다. 기존에 배운 것을 바탕으로 새 기능을 작성하는 것이기 때문에 배포 외 새로 배우는 개념은 없었다.

목차

  1. Vercel을 사용한 배포
  2. 마지막 과제

Vercel을 사용한 배포

Vercel은 Next.js의 제작한 회사이자 Next.js 배포 서비스 이름으로 Next.js에 특화된 배포 서비스를 제공한다는 장점을 가지고 있다. Github에 프로젝트가 있으면 Github연동으로 바로 프로젝트를 연결해서 배포도 가능하다. Firestore에는 Vercel을 통해 얻은 도메인을 등록해주는 정도의 과정만 수행하면 배포는 끝난다.

아래는 참고자료.

 

Next.js 배포하기(Vercel 사이트 이용하기)

친구들! Next.js로 사이트 만들었는데, 이제 배포할 차례야! 집에 서버가 있다면 간단히 빌드 및 실행하는 걸로 가능해! 먼저, 변경사항이 있다면 빌드! - Pre-rendering할 페이지들 미리 만들어주는 과

ppsu.tistory.com

 

마지막 과제 (추가 기능 구현)

마지막 과제의 목록은 다음을 구현하는 것이었다.

 

  • /controllers/menuList/menu_list.controller.ts findAllByOwnerId
  • /controllers/menuList/menu_list.controller.ts addMenuList
  • MenuListModel.update 메서드 만들어보기

참고로 마지막 것은 난이도 상의 추가 과제였다.

@/controllers/menuList/menu_list.controller.ts

 

export default class MenuListController {
  static async findAllByOwnerId(req: Request, res: Response) {
    const token = req.headers.authorization;
    if (token === undefined) {
      return res.status(400).end();
    }
    let userId = '';
    try {
      const decodedIdToken = await FirebaseAdmin.getInstance().Auth.verifyIdToken(token);
      userId = decodedIdToken.uid;
    } catch (err) {
      return res.status(400).end();
    }
    if (userId === '') {
      return res.status(401).json({
        text: '조회할 권한이 없습니다',
      });
    }
    try {
      const menuListResp = await MenuListModel.findAllByOwnerId({ ownerId: userId });
      return res.status(200).json(menuListResp);
    } catch (err) {
      return res.status(500).send(err.toString());
    }
  }
  
  static async addMenuList(req: Request, res: Response) {
    const token = req.headers.authorization;
    if (token === undefined) {
      return res.status(400).end();
    }
    let userId = '';
    try {
      const decodedIdToken = await FirebaseAdmin.getInstance().Auth.verifyIdToken(token);
      userId = decodedIdToken.uid;
    } catch (err) {
      return res.status(400).end();
    }
    const validateReq = validateParamWithData<{ body: Pick<IMenuListItem, 'title' | 'desc' | 'menu'> }>(
      {
        body: req.body,
      },
      JSCAddMenuList,
    );
    if (validateReq.result === false) {
      return res.status(400).json({
        text: validateReq.errorMessage,
      });
    }
    try {
      console.log(validateReq.data.body);
      const result = await MenuListModel.add({ ...validateReq.data.body, ownerId: userId });
      return res.status(200).json(result);
    } catch (err) {
      return res.status(500).send(err.toString());
    }
  }
}

@/controllers/menuList/menu_list.controller.ts

class MenuListType {
  // ...(생략)...
  
  async update({
    ownerId,
    id,
    title,
    desc,
    menu,
  }: {
    ownerId: string;
    id: string;
    title?: string;
    desc?: string;
    menu?: IBeverage[];
  }) {
    const docRef = this.MenuListDoc(id);
    await FirebaseAdmin.getInstance().Firestore.runTransaction(async (transaction) => {
      const doc = await transaction.get(docRef);
      if (doc.exists === false) {
        throw new Error('not exist');
      }
      const oldDoc = doc.data() as Omit<IMenuListItem, 'id'>;
      if (ownerId !== oldDoc.ownerId) {
        throw new Error('수정할 권한이 없음');
      }
      const setData: Omit<IMenuListItem, 'id'> = {
        ...oldDoc,
      };
      if (title !== undefined) {
        setData.title = title;
      }
      if (desc !== undefined) {
        setData.desc = desc;
      }
      if (menu !== undefined) {
        setData.menu = menu;
      }
      await transaction.update(docRef, setData);
    });
  }
}

사실 스터디 리더님이 정답에 가까운 힌트를 다 주셨기도 하고 이전에 배운 내용 그대로 복습하는 내용에 가까워서 특별히 고민할 내용은 없었다. 이에 따라, 지금까지 한 내용을 복습한다고 생각하고 과제를 진행했다.