Posted at

TypeScriptベースなRequestの共通化


前置き


  • App: ionic

  • Web: Angular

  • API: Nest.js

僕たちのチームのフレームワーク採用はこんな感じで全部Angularベース。

API Docはapi blueprintあたりを採用。

「でもこれ、フロントエンド/バックエンドで同じような実装するじゃん...無駄じゃね」

と思いはじめて実験的に取り組んでみてる構成を紹介します。


Requestクラスを共通化する

Requestクラスを別リポジトリに分けて、git moduleとして扱っちゃう作戦です。

構成とコマンドは以下のような感じ。

今回はUser追加のリクエストを共通化する例です。


ディレクトリ構成

├── app

│   ├── tsconfig.json
│   ├── package.json
│   └── src
│       └── common (submodule: common)
├── api
│   ├── tsconfig.json
│   ├── package.json
│   └── src
│       └── common (submodule: common)
└── common
    ├── tsconfig.json
    ├── package.json
    └── Requests
        └── AddUserRequest.ts


サブモジュールの追加

$ git submodule add ./src/common

$ npm i ./src/common


RequestClass

class-validatorにしたがって以下のようにすると楽ちんです。


BaseRequest.ts

import { validate } from "class-validator";

export class BaseRequest {
async validate(): Promise<boolean> {
const errors = await validate(this);

if (errors.length > 0) {
throw new Error(errors.toString());
} else {
return true;
}
}
}



AddUserRequest.ts

import * as v from "class-validator"

export class AddUserRequest extends BaseRequest{
@v.IsNotEmpty()
id: string;

@v.IsDate()
@v.IsOptional()
birthday: Date;
}


こうしておくことでNest.js側では通常通りにValidationがかかります。

@Post("/user")

@HttpCode(200)
async create(@Body() params: AddUserRequest) {
// 処理
}

Angularやionic側ではclass-transformerを使ってvalidateが可能です

import { plainToClass } from "class-transformer";

const req: AddUserRequest = plainToClass(request);

if (await req.validate()) {
// 処理
}