前置き

  • 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()) {
    // 処理
}

元記事はこちら

TypeScriptベースなRequestの共通化