aspidaとNestJSでHTTPClientにも型定義しながら開発するぞ!!!!!!!
aspidaとNestJSを使って気持ちがいい開発がしたい!したくない?
今回もお試しリポジトリが存在します.NestJS x aspida x Reactの環境で作っています.是非お試しください
なにするの?
NestJSはにはSwaggerModuleがありOpenAPIでしゃべることが可能になります.また, aspidaにはopenapi2aspidaというサブライブラリが存在します.この2つの組み合わせによりNestJS -> OpenAPI -> aspidaができるようになりNestJSでControllerを書くと自動的にHTTPClientの型定義が生成されるという感じになります.バックエンドを書くとフロントエンドに必要なコードが生成されるのは気持ちがいいですね.
OpenAPI経由でaspidaの設定ファイルが吐かれるのでNestJSに限らずいろいろは場面で使えるかと思います.今回はその一例としてNestJSを利用しています.
aspidaとは
HTTPClientに型をつけてくれるライブラリです.GETクエリ, Postパラメータはもちろん, Formデータにも型がつくらしい. しかもURIも保管してくれたりします.
使用感はこんな感じです
今回は /api/user/
に問い合わせるとUser
オブジェクトが返ってくるようなapiを作りました.
導入方法
yarn add @aspida/axios axios
初期設定だと<root>/apis/
以下にエンドポイントと同じ名前のディレクトリを切って設定ファイルを置いていくことになります.この設定ファイルを読んで<root>/apis/$api.ts
が作成されます.
aspidaのビルド設定ファイルは公式を見てください aspida/packages/aspida at master · aspidajs/aspida · GitHub
例えば/api/user
というエンドポイントが生えていたとすると,次のようにファイルを作って設定を書けばおkです
export interface Methods { get: { resBody: Types.User } }
作成後に
yarn aspida --build
で<root>/apis/$api.ts
が作られ型定義されたHTTPClientを使用することができます.
aspidaの設定ファイルは必ずHTTPクライアントをラップする必要があるので,実際使用するときはこのようなutil関数を作っておくと楽だと思います.
import client from "apis/$api"; import aspida from "@aspida/axios"; export const api = client(aspida());
openapi2aspida
OpenAPI形式のjsonをHTTP通信形式で受け取り,aspidaの設定ファイルを自動で作ってくれます.めちゃくちゃ便利.
ルートにaspida.config.json
を作っておき
module.exports = { input: "apis", // outputディレクトリ, openapi: { inputFile: "http://localhost:3000/swagger-json" } }
でおkです.サーバを起動した状態で, openapi2aspida --build
でaspidaの設定ファイルが全て自動生成されます.便利すぎる・・・・
2回目移行ビルドするときはoutputディレクトリ丸ごと消しておく必要があります.
fatal: destination path 'apis' already exists and is not an empty directory.
NestJSについて
Node.jsにおいてバックエンドサーバといえば, Express一強みたいなところがありましたが,最近伸びているバックエンドフレームワークです.Angulerに近い書き心地で様々な機能を後からバシバシ入れることができるプログレッシブフレームワークになっています.Star数も22.5kとかなり多くなってきていて今注目のフレームワークって感じがしてきますね
今回はNestJSには深く触れず, SwaggerModuleを入れるところから始めていきたいと思います.
2019NestJSのアドベントカレンダーに少し参加したので興味のある人はこちらへ
SwaggerModuleを入れてOpenAPIを喋れるようにする
公式ドキュメントにSwaggerModuleの導入の仕方が書いてあるのでそちらを参考に進めていきます.
必要なモジュールを入れる
yarn add @nestjs/swagger swagger-ui-express
main.tsを次のように書き換える
import { NestFactory } from "@nestjs/core"; import { SwaggerModule, DocumentBuilder } from "@nestjs/swagger"; import { AppModule } from "./app.module"; async function bootstrap() { const app = await NestFactory.create(AppModule); app.setGlobalPrefix("api"); // frontendのrenderを/においているのでNestJSで定義される全てのControllerをapi/xxxにしておく // 公式とほとんど同じ const options = new DocumentBuilder() .setTitle("API description") .setVersion("1.0") .addServer("http://localhost:3000/") .build(); const document = SwaggerModule.createDocument(app, options); SwaggerModule.setup("swagger", app, document); await app.listen(3000); } bootstrap();
ここで現在これは修正されていますaddServer
をやっておかないとopenapi2aspida
が実行できないので気をつけましょう.
この行で落ちます
const options = new DocumentBuilder() .setTitle("API description") .setVersion("1.0") .addServer("http://localhost:3000/") .build();
これだけでNestJSがOpenAPIを喋れるようになりました.
yarn start:dev
をやってから
特に何もしていなければhttp://localhost:3000/swaggerでこのような画面を見れると思います.
また,http://localhost:3000/swagger-jsonでOpenAPIを喋っているのがJSON形式でわかります
なんの型が返ってくるかを明示するためにapp.controller.ts
を次のように書き換えます
import { Controller, Get, Post, Body } from "@nestjs/common"; import { AppService } from "./app.service"; import { ApiTags, ApiCreatedResponse } from "@nestjs/swagger"; @ApiTags("AppController") @Controller() export class AppController { constructor(private readonly appService: AppService) {} @Get() @ApiCreatedResponse({ type: String }) // ここでstringが返ってくることを書いておく getHello(): string { return this.appService.getHello(); } }
これでopenapi2aspidaで型を自動生成する準備は万端です.実際にビルドして使用感を確かめてみましょう
NestJSから吐かれるOpenAPIからaspidaの設定ファイルを生成してみる
NestJSを次のコマンドで起動します
yarn start:dev
http://localhost:3000/swagger-jsonが生きてることを確認し,aspida.config.js
に以下の設定が書いてあれば準備はおkです
module.exports = { input: "apis", openapi: { inputFile: "http://localhost:3000/swagger-json" } }
このコマンドを実行すれば自動生成されます
rm -rf apis yarn openapi2aspida --build
たったこれだけで<root>/apis/$api.ts
が生成されました.
すごいですよね!!! あとはこれをフロントエンドのコードで使うだけ!OpenAPIをメンテしていく意味も出てくるし一石二鳥のライブラリだと思います.
まとめ
去年の12月ごろにも一度使用していたのですが,かなりのアップデートがかかっていてびっくりしました. naporitan.hatenablog.com
NestJSとaspidaを使えばすべてTSの世界でwebの世界を渡り歩けるようになりました.今実戦投入するプロジェクトにこの構成をとっていますが,いい感じです.
副作用として,バックエンドでAPIを書き換えるとき影響範囲がTSの型チェックで落ちたところを修正すればよくなるのでAPI変更の際の精神負荷も少し軽減される気もします.
バックエンドでAPIを作成するとすぐ型安全な状態でそのAPIにアクセスできると言うのは圧巻だと思います. aspida流行れ・・・・!!!