aspidaとNestJSでHTTPClientにも型定義しながら開発するぞ！！！！！！！

この記事は同名記事の著作者から許可をいただいて転載しました
[aspidaとNestJSでHTTPClientにも型定義しながら開発するぞ！！！！！！！ - なぽろぐ](https://naporitan.hatenablog.com/entry/2020/03/29/154618)

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">NestJS SwaggerModuleでaspidaのコンフィグが自動生成できる！！<br>コントローラー書いたらHTTPClientが出来上がる感動がすごい<br>aspidaとNestJSでHTTPClientにも型定義しながら開発する…<a href="https://t.co/eRnnT5Jl8B">https://t.co/eRnnT5Jl8B</a></p>&mdash; naporitan🍆🍆 (@naporin24690) <a href="https://twitter.com/naporin24690/status/1244154247312060416?ref_src=twsrc%5Etfw">March 29, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## aspidaとNestJSを使って気持ちがいい開発がしたい！したくない？

今回もお試しリポジトリが存在します．NestJS x aspida x Reactの環境で作っています．是非お試しください
[naporin0624/aspida-and-nestjs - github.com](https://github.com/naporin0624/aspida-and-nestjs)

## なにするの？

NestJSにはSwaggerModuleがありOpenAPIでしゃべることが可能になります．また, aspidaにはopenapi2aspidaというサブライブラリが存在します．この2つの組み合わせによりNestJS -> OpenAPI -> aspidaができるようになりNestJSでControllerを書くと自動的にHTTPClientの型定義が生成されるという感じになります．バックエンドを書くとフロントエンドに必要なコードが生成されるのは気持ちがいいですね．

OpenAPI経由でaspidaの設定ファイルが吐かれるのでNestJSに限らずいろいろな場面で使えるかと思います．今回はその一例としてNestJSを利用しています．

## aspidaとは
[aspidajs/aspida - github.com](https://github.com/aspidajs/aspida/tree/master/packages/aspida)

HTTPClientに型をつけてくれるライブラリです．GETクエリ, Postパラメータはもちろん, Formデータにも型がつくらしい. しかもURIも補完してくれたりします．

使用感はこんな感じです

今回は`/api/user/`に問い合わせると`User`オブジェクトが返ってくるようなapiを作りました．![eb2b0d2c713b05b725e93694ec314497.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63528/49ae08e9-ed5a-e5fb-bc45-02dfb55bd1f3.gif)

### 導入方法

```bash
yarn add @aspida/axios axios
```

初期設定だと`<root>/apis/`以下にエンドポイントと同じ名前のディレクトリを切って設定ファイルを置いていくことになります．この設定ファイルを読んで<root>/apis/$api.tsが作成されます．

aspidaのビルド設定ファイルは公式を見てください [aspida/packages/aspida at master · aspidajs/aspida · GitHub](https://github.com/aspidajs/aspida/tree/master/packages/aspida#tips)

例えば`/api/user`というエンドポイントが生えていたとすると，次のようにファイルを作って設定を書けばおkです

```typescript:/apis/api/user.ts
export interface Methods {
  get: {
    resBody: Types.User
  }
}
```
作成後に

```bash
yarn aspida --build
```
で`<root>/apis/$api.ts`が作られ型定義されたHTTPClientを使用することができます．

aspidaの設定ファイルは必ずHTTPクライアントをラップする必要があるので，実際使用するときはこのようなutil関数を作っておくと楽だと思います．

```typescript
import client from "apis/$api";
import aspida from "@aspida/axios";

export const api = client(aspida());
```

## openapi2aspida
OpenAPI形式のjsonをHTTP通信形式で受け取り，aspidaの設定ファイルを自動で作ってくれます．めちゃくちゃ便利．

ルートに`aspida.config.js`を作っておき

```javascript:aspida.config.js
module.exports = {
  input: "apis", // outputディレクトリ,
  openapi: { inputFile: "http://localhost:3000/swagger-json" }
}
```
でおkです．サーバを起動した状態で,`openapi2aspida --build`でaspidaの設定ファイルが全て自動生成されます．便利すぎる・・・・

2回目移行ビルドするときはoutputディレクトリ丸ごと消しておく必要があります．

```bash
fatal: destination path 'apis' already exists and is not an empty directory.
```

## NestJSについて
Node.jsにおいてバックエンドサーバといえば, Express一強みたいなところがありましたが，最近伸びているバックエンドフレームワークです．Angulerに近い書き心地で様々な機能を後からバシバシ入れることができるプログレッシブフレームワークになっています．Star数も22.5kとかなり多くなってきていて今注目のフレームワークって感じがしてきますね
[nestjs/nest - github.com](https://github.com/nestjs/nest)

今回はNestJSには深く触れず, SwaggerModuleを入れるところから始めていきたいと思います．

[2019NestJSのアドベントカレンダー](https://qiita.com/advent-calendar/2019/nestjs)に少し参加したので興味のある人はこちらへ

### SwaggerModuleを入れてOpenAPIを喋れるようにする
公式ドキュメントにSwaggerModuleの導入の仕方が書いてあるのでそちらを参考に進めていきます．
[Documentation | NestJS - docs.nestjs.com](https://docs.nestjs.com/recipes/swagger)

必要なモジュールを入れる

```bash
yarn add @nestjs/swagger swagger-ui-express
```
main.tsを次のように書き換える

```typescript: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`が実行できないので気をつけましょう．

[この行](https://github.com/aspidajs/aspida/blob/master/packages/openapi2aspida/src/buildV3.ts#L265)で落ちます
（※転載者追記：openapi2aspidaのv0.4.1で修正されてaddServerが不要になりました）

```typescript
 const options = new DocumentBuilder()
    .setTitle("API description")
    .setVersion("1.0")
    .addServer("http://localhost:3000/")
    .build();
```
これだけでNestJSがOpenAPIを喋れるようになりました．

```bash
yarn start:dev
```
をやってから

特に何もしていなければhttp://localhost:3000/swagger でこのような画面を見れると思います．
![39ec811b4299b46b0075f3914438af34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63528/623b6e36-90b9-9d5e-ce33-397f538e7838.png)
また，http://localhost:3000/swagger-json でOpenAPIを喋っているのがJSON形式でわかります

なんの型が返ってくるかを明示するために`app.controller.ts`を次のように書き換えます

```typescript: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を次のコマンドで起動します

```bash
yarn start:dev
```
http://localhost:3000/swagger-json が生きてることを確認し，`aspida.config.js`に以下の設定が書いてあれば準備はおkです

```javascript:aspida.config.js
module.exports = {
  input: "apis",
  openapi: { inputFile: "http://localhost:3000/swagger-json" }
}
```
このコマンドを実行すれば自動生成されます

```bash
rm -rf apis
yarn openapi2aspida --build
```
たったこれだけで`<root>/apis/$api.ts`が生成されました．
<img width="600" alt="20200329084534.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63528/6e09f6f3-585b-ca5c-9951-e68107e08044.png">
すごいですよね！！！ あとはこれをフロントエンドのコードで使うだけ！OpenAPIをメンテしていく意味も出てくるし一石二鳥のライブラリだと思います．

## まとめ
去年の12月ごろにも一度使用していたのですが，かなりのアップデートがかかっていてびっくりしました．
[【NestJSアドベントカレンダー】NestJSとwebpack-dev-middlewareを組み合わせる - naporitan.hatenablog.com](https://naporitan.hatenablog.com/entry/2019/12/25/031421)

NestJSとaspidaを使えばすべてTSの世界でwebの世界を渡り歩けるようになりました．今実戦投入するプロジェクトにこの構成をとっていますが，いい感じです．

副作用として，バックエンドでAPIを書き換えるとき影響範囲がTSの型チェックで落ちたところを修正すればよくなるのでAPI変更の際の精神負荷も少し軽減される気もします．

バックエンドでAPIを作成するとすぐ型安全な状態でそのAPIにアクセスできると言うのは圧巻だと思います． <font size="10" color="Red">aspida流行れ・・・・！！！</font>