ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [TIL] 스파르타) Ch.3 개인 과제 - 3일 차 (Joi, git commit --amend)
    TIL 2024. 5. 15. 22:01

     > 휴일이지만 할 일이 없어서 만들어둔 프로젝트 스크립트들을 손보고 기능을 추가해봤다. 발생했던 문제와 새롭게 배운 것들을 정리해보았다.

     

    학습 키워드: javascript, Node.js, Joi, express, MongoDB, mongoose, pre, git, amend

     

    1. Joi

    1) What is it?:

     JS에서 여러가지 데이터 validation을 자체 schema를 통해 직관적으로 수행할 수 있도록 도와주는 라이브러리다.

     

    2) Before applying (regex):

     앞서 언급했듯이 직관적인 validation을 수행할 수 있도록 하는게 목적이라서 방식이 상당히 간단하다. 프로젝트에 적용하기 전과 후의 스크립트를 비교하며 알아보자.

    // items-validator.middleware.js
    
    const isNotNumber = /[^0-9]/;
    
    const itemValidator = {
      itemCodeValidation: (req, res, next) => {
        const item_code = req.body.item_code || req.params.item_code;
        if (isNotNumber.test(item_code))
          return res
            .status(400)
            .json({ errorMessage: `Invalid item_code: ${item_code}` });
        next();
      },
     
     ...
     
    };

     먼저, 아이템 api 이용 시에 진행되는, Joi를 사용하기 전의 validation middleware의 스크립트 일부를 가져왔다. itemCodeValidation은 아이템의 code가 숫자의 형태인지, 존재는 하는지를 확인하기 위한 유효성 검증 작업이다. 최대한 압축한다고 regex와 if구문의 condition을 이용했는데, 검색하다가 보니 js의 regex가 동작이 느리다는 이야기를 여기저기서 읽었다. JS의 regex 자체 구현 퀄리티가 안좋아서 그렇다는데 스크립트를 직접 읽어보지는 않아서 사실 여부는 확인하지 못했다.

     

     짧고 간결해 보이지만, 현재는 모든 케이스를 다 걸러주고 있지도 않으며, regex를 쓰지 않고 모든 조건을 검증하도록 바꾸면 if 구문이 많아지게 되므로 결국 스크립트가 길고 지저분해져서 알아보기가 힘들어진다. 그래서 대안으로 강의에서 배운 Joi를 사용해보기로 했다.

     


    3) After applying (Joi):

    // items-validator.middleware.js
    import Joi from "joi";
    
    const itemCodeSchema = Joi.object({ // #1
      item_code: Joi.number().integer().min(1).required(), // #2
    }).unknown(true); // #3
    
    const itemValidatorJoi = {
      itemCodeValidation: (req, res, next) => {
        const target = {
          item_code: req.body.item_code || req.params.item_code,
        };
    
        const validation = itemCodeSchema.validate(target); // #4
    
        if (validation.error) {
          console.log("itemCodeValidation: ", validation.error.message);
          let msg = `Invalid item_code: ${target.item_code}`;
          return res.status(400).json({ errorMessage: msg });
        }
    
        next();
      },
      
      ...
      
    }

     얼핏 보기에는 regex보다는 약간 길어졌는데, regex보다 더 많은 케이스를 걸러내기도 하고, 뭔가 조건이 더 추가되더라도 이 이상 길어지지 않기 때문에 실제로는 더 짧은 스크립트라고 볼 수 있다.

     

     Joi로 validation을 구현하려면 일단 #1 처럼 Joi schema를 정의해주어야 한다. Joi.object의 parameter에 객체를 넣어주는데, 여기서 객체 내 key 값의 이름을 실제 request에서 받게 되는 key와 동일한 이름으로 설정 해줘야한다. 그 다음 해당 key의 value에서 validation에 사용될 조건의 목록을 작성해준다. 위의 예시(#2)에서는, required로 undefined나 null을 걸러주고, number와 integer이면서 최소 1 이상의 정수 값만 받을 수 있게 설정해두었는데, 이렇게 한 줄 안에서 한 개 key의 모든 조건을 다 처리할 수 있어서 상당히 짧고 직관적이게 변한다.

     

     #4 에서 실제 validation을 진행하게 되는데, 위에서 정의한 schema에 대해 validate()를 호출하고, 파라미터로 검증할 객체를 넘겨주면 된다. 주의할 점은 req 객체 내에서 알려지지 않은(unknown) 키 값이 있다면 검증을 실패하는데, req.body 같은 경우 기본 body에 들어있는 모든 키를 제외하고 form 등을 이용해 추가로 받아온 key 값 중 schema에 없는 값 들이 여기에 걸려서 validation이 실패할 수 있다. 만약 위에서 처럼 한 가지 항목만 검증하고 나머지는 무시하려면 #3 처럼 schema의 끝에 .unknown(true)를 붙여주면 된다.

     

     여기서 더 짧게 만드려면 validate 대신 validateAsync를 사용해서 validation이 끝나기 전에 검증 실패 지점에서 즉시 오류를 throw 하도록 설정할 수 있다. 이렇게 한 뒤 try catch로 에러를 캐치해서 원하는 방향으로 처리해주면 된다. 가능한 구조를 고민해보고 프로젝트에 적용해 볼 예정이다.

     

     

    4) Why use it?:

     지금처럼 적은 양의 데이터가 아닌 여러개의 key를 가진 큰 data를 검증해야 하는 경우 validation이 상당히 복잡해져서 알아보기도 어렵고 유지/보수가 힘들어진다. Joi를 사용하면 데이터 검증 로직을 Schema의 형태로 정의하여 직관적으로 관리할 수 있게 된다. 검증 로직 구현 및 수정에 시간을 많이 쓰는 것은 여러모로 효율적이지 못하기 때문에 이렇게 간결하게 구현할 수 있는 라이브러리를 적극적으로 이용하는 것이 좋다.

     

     

    2. git commit --amend

    1) What is it?:

     프로젝트 작업을 끝내고 commit을 하다가 실수로 작업 내역을 하나 빠뜨렸는데, 커밋을 다시 되돌리기엔 메세지도 길고 파일도 많아서 방법이 없나 하면서 찾아보게 됐다. Amend는 git에서 마지막으로 commit한 메세지 내용을 수정할 수 있는 기능이다. 일단 --amend 자체는 commit 외의 다른 곳에서도 쓰이는 듯 하지만, 이번에는 commit 위주로 알아보겠다.

     

    2) How does it work?:

    git commit -m "Rename: characters.validator.js > characters-validator.middleware.js
    Update: errorHandler to handle the new error class
    Add: CharacterNotFoundError class
    Update: characters router throws CharacterNotFoundError
    Update: pass catched err to the next middleware"
    # realized I forgot to add 'Update: use Joi for characters validation'
    git commit --amend

     오늘 실제로 겪었던 상황을 재연해봤다. 약간 긴 메세지를 작성하고 commit을 완료했는데, 잠시 후에 작업 내용을 한 줄 빼먹었다는 사실을 알게됐다. 이럴 때 맨 아랫 줄 처럼 git commit --amend를 입력해주면 가장 최근 commit을 수정할 수 있는 vi 에디터로 진입하는데, 여기서 원하는 위치까지 화살표 키로 이동한 뒤 I 키를 누르면 insert 모드로 진입해서 문자를 지우거나 채워 넣을 수 있다. S 키를 눌러 insert 모드에 진입할 경우 커서 위치의 문자가 삭제되는 것에 주의하자. 수정 작업이 완료되면 esc를 눌러 insert 모드를 종료하고 :wq를 입력해 저장 후 종료해 주거나, 수정 사항을 취소하고 싶다면 :q!를 사용하여 저장하지 않고 에디터를 종료할 수 있다. 그 외 자세한 vi 에디터 사용법은 링크를 참고하자.

    실제 commit에 --amend를 사용한 화면, 앞의 예시와는 무관한 commit이다

     - 하단에 위치한 파란색 글씨에 #으로 시작하는 부분은 무시된다.

     - amend를 통해 commit 메세지를 수정하고 저장하면 실제 commit이 새로운 commit으로 대체되는 방식인데, history가 추가되거나 하지는 않지만 commit이 교체되기 때문에 remote에 공유되고 있는 commit(스크린샷에서 처럼 github에서 merge하며 남은 commit 기록 등)에 사용하면 문제가 발생할 수 있다. 로컬의 개인용 branch에 존재하는 commit을 대상으로만 사용하는 것을 권장한다.

     

    git commit --amend -m "Update: new commit message"

     amend 뒤에 -m 옵션을 입력하여 vi 에디터를 사용하지 않고 아예 새로운 commit 메세지로 변경해 줄 수도 있다.

     

    # Edit hello.py and main.py
    git add hello.py
    git commit 
    # Realize you forgot to add the changes from main.py 
    git add main.py 
    git commit --amend --no-edit

     게시글 하단에 링크한 atlassian에서 가져온 예시인데, --amend 뒤에 --no-edit을 붙여주면 commit 메세지의 수정 없이 stage된 파일만 마지막 commit에 추가해주는 것도 가능하다고 한다.

     

     

    4) Why use it?:

     파일을 하나하나 stage하고 commit 메세지를 작성하다보면 파일이든 메세지든 무언가 하나를 빠뜨리는 경우가 빈번하다. 이럴 때 마다 커밋을 되돌린다면 작업이 매우 수고로워질 것이다. 따라서 앞으로는 --amend를 적극 활용하여 문제를 쉽게 해결하도록 하자.

     

     

    --

     

    REFERENCES:

     

     

    Node.js 게임서버 입문 주차 개인 과제 | Notion

    함께 학습을 진행할 팀을 확인해보세요!

    teamsparta.notion.site

     > 과제 specification

     

    GitHub - donkim1212/ch3-item-simulator: Chapter3 개인 과제

    Chapter3 개인 과제. Contribute to donkim1212/ch3-item-simulator development by creating an account on GitHub.

    github.com

     > 개인 프로젝트 repository

     

    커밋 메시지 변경 - GitHub Docs

    커밋 메시지에 명확하지 않거나 잘못되거나 중요한 정보가 포함된 경우 로컬에서 수정하고 새 메시지와 함께 새 커밋을 GitHub에 푸시할 수 있습니다. 커밋 메시지를 변경하여 누락된 정보를 추

    docs.github.com

     > github.com, 커밋 메시지 변경

     

    joi.dev

     

    joi.dev

     > joi.dev

     

    Unix/Linux - The vi Editor Tutorial

    Unix/Linux - The vi Editor Tutorial - In this chapter, we will understand how the vi Editor works in Unix. There are many ways to edit files in Unix. Editing files using the screen-oriented text editor vi is one of the best ways. This editor enables you to

    www.tutorialspoint.com

     > tutorialspoint.com, "The vi Editor Tutorial"

     

    git amend | Atlassian Git Tutorial

    Common use cases for overwriting committed snapshots in Git. History rewriting commands: git commit--amend, git rebase, git rebase -i and git reflog.

    www.atlassian.com

     > atlassian.com, "git amend"

    728x90
Designed by Tistory.