데코레이터를 곁들인 Express Mock api 만들기

poyal·2024년 7월 2일
1
post-thumbnail

일단 나는 프론트앤드 개발자이다.

예전부터 프론트 앤드에서 Mock api를 만들어서 개발 문화에 적용하여 작업 했던적이 있었다. 단발성 작업으로 SI 프로젝트에서 사용하고 잊었던 적들이 많았었다. 예전에는 Express + mongodb를 활용해서 만들기도 했었고, http-server + json을 활용해서 간이 Mock api를 만들기도 했었다. 연차가 늘어가면서 자연스럽게 거추장스럽게 느껴졌지만 요즘 하는 TDD와 Stroybook을 적용하면서도 다시 필요하게 느껴졌다.

이게 현실이다...

현실 이미지1

프로젝트를 시작하면 개발 계획을 아름답게 설정하고 프로젝트를 시작한다. 그러다가 분석 설계와 개발 일정이 딜레이 되기 시작된다. 여러 사유가 있겠지만 불가피하게 늘어지게 된다. 많은 사유가 있겠지만 이러한 현상이 빈번하게 발생한다는 것이다.

현실 이미지2

그러면 기한에 다달아서 담당자에서 문의가 오게된다. 언제 쯤 볼수 있을까요? 라고하면 이렇게 대답하게 된다. 어... 엄... API가 나오지 않아서... 더 걸릴거 같습니다... 그렇다고 이상적으로 프론트앤드의 기한을 늘려주는 그런 아름다운 일은 일어나지 않는다. 결국에는 마지막 단계인 프론트 앤드가 기한을 지켜서 개발해야 된다.

현실 이미지3

Mock api를 도입하여 이런 개발 플로우를 바란다. 개발 스펙이 정해지면 백엔드와 같이 개발을 할수 있어서 기간을 세이브하는걸 기대한다. 기간을 세이브 하는 만큼 변경이나 코드질에 더 투자하는걸 기대한다.

요건

  • 빠르게 추가 해야 한다.
  • 독립적으로 실행 해야 한다.
  • 프로젝트에 관련이 안된 독립 프로젝트 이여야 한다.
  • 프론트 엔드에서 사용하는 모델은 그대로 복붙 할수 있어야 한다.
  • 상태관리를 해서 CURD 정상 동작 해야한다.
  • 샘플 데이터가 없을 때 랜덤한 데이터를 생성할수 있어야 한다.
  • 파일 업로드하고, 파일에 접근 할수 있어야 한다.
  • 변경된 데이터는 git에 올라가지 않았으면 좋겠다.
  • 구현방식은 typescript + express + @decorators/express 사용 했으면 좋겠다.

구현

// sample.controller.ts
@Controller('/samples')
export default class SampleController {
  private service: SampleService = Container.resolve(SampleService);

  @Get('')
  getList(@Res() res: Response) {
    try {
      res.status(200).json(this.service.getList());
    } catch (error: unknown) {
      res.status(406).json(error);
      console.log(error);
    }
  }

  // ...
}

// sample.service.ts
export default class SampleService {
  private validate: ValidateService = Container.resolve(ValidateService);
  private mapper: Mapper = Container.resolve(Mapper);

  getList(): SampleModel.Response.FindAll[] {
    return store.getList();
  }

  // ...
}

// sample.store.ts
class SampleStore extends StoreAbstract<SampleEntity.Sample> {
  constructor() {
    super({
      path      : 'sample/real',
      name      : 'sample.json',
      primaryKey: 'id',
      data      : DEFAULT,
      entity    : SampleEntity.Sample,
    });
  }

  getList(): SampleModel.Response.FindAll[] {
    let items: SampleModel.Response.FindAll[] = this.mapper.toArray(SampleModel.Response.FindAll, super.getAll());
    return this.mapper.toPlain(items);
  }

  // ...
}

export const store: SampleStore = new SampleStore();

기본 CURD는 해당 코드만 붙여 넣으면 다 기능하게 구현했다.

유사 상태관리

Mock api에서 상태 상태 관리가 필요하지만, 라이브러리를 활용하는 그러한 상태관리 까지는 필요가 없었다.
어차피 로컬에서 돌아가는 Mock api 특성상 DB까지도, 하드한 상태관리 라이브러리 까지도 필요가 없었다.
그래서 실행시에 샘플데이터를 생성하는 유사 상태관리를 만들었다.

유사 상태관리

상태관리에서 파일을 읽고 쓰는 형태이다. 파일이 있으면 기존의 파일을 사용하고, 없으면 정의된 샘플로 생성한다.

샘플 데이터 파일 생성

샘플 데이터를 생성할때 무작위 데이터를 생성 하는게 필요하다고 생각한다. 샘플 데이터를 만드는것도 일이기 때문이다 만약 랜덤한 데이터를 무작위로 만들어 준다면 편할 것이다.

{
    "id": 711,
    "name": "name-GLH6dcUmrqZPRoQclE9wwNtK7f2mVCqM",
    "flag": true,
    "enumA": "TYPE_A_2",
    "enumB": "TYPE_B_3",
    "date": "20240429",
    "dateTime": "2024/06/25 16:11:59",
    "time": "11~37~20",
    "item": {
      "id": 337,
      "name": "name-WQmwOFuVK9WjRB85DY0NkvZ17o4fWTTu",
      "flag": true
    },
    "items": [
      {
        "id": 8284,
        "name": "name-R7JZ9qDNrQa1cNV8CjI67542Oe1X8o5V",
        "flag": true
      },
      {
        "id": 7581,
        "name": "name-kty7OvCcDabcBRxuTKbntKfGi2f5fVgp",
        "flag": true
      }
    ]
  }

무작위로 모델의 값을 읽어서 랜덤 값을 만들어준다. 숫자, 문자, enum, 날자, 시간등 모든 사용할수 있는 모든 데이터가 랜덤이다.

실행

List

List

Page

Page

One

One

Add

Add

Modify

Modify

Delete

Delete

Validate Error

Validate Error

결과

이전에 포스팅한 Story book 과 단위테스트에서도 Mock api를 사용하도록 변경하였다. 매번 TDD를 진행하면서 문제가 되는 부분이 인증이나 실사용 데이터가 문제였는데, 이부분이 해결이 되었다. 개발자가 코드량이 적게 만들수 있게끔 만들고 싶었다. 그렇게 잘나온거 같아서 뿌듯한거 같다.

참조

0개의 댓글