OpenAPIGeneratorを使ってNuxt.js/Axiosのクライアントを自動生成する

# TL;DR

APIリクエスト周り楽できないかな〜と探した結果OpenAPIGeneratorにたどり着きました。
試行錯誤した結果、簡単にかつそれなりの結果が得られたので記事にします。

# 前提条件
- Nuxt.js（v2.15.7）
- Typescript
- Axios
- Auth
- OpenAPI
- docker

# 手順
## クライアントの生成
[公式のdockerイメージ](openapitools/openapi-generator-cli)があるので、そちらを利用します。
変換先の形式については[様々な言語・フレームワーク](https://github.com/OpenAPITools/openapi-generator/tree/master/docs/generators)に対応していますが、
今回はその中の[typescript-axios](https://github.com/OpenAPITools/openapi-generator/blob/master/docs/generators/typescript-axios.md)を利用します。

まず、以下のようなdocker-composeファイルを用意します。

```yaml:docker-compose.yml
version: '3'
services:
  openapi-generator: 
    image: openapitools/openapi-generator-cli:latest-release
    volumes:
      - ".:/local"
    command: generate -i /local/docs/api-docs.yaml -g typescript-axios -o /local/hogehoge/types/client-axios
```

`docker compose up`をした出力結果は以下のような感じ。

```
.
├── assets
├── components
├── layouts
├── middleware
├── pages
├── plugins
├── static
├── store
└── types
    └── client-axios
        ├── api.ts \\メインファイル
        ├── base.ts
        ├── common.ts
        ├── configuration.ts
        ├── git_push.sh
        └── index.ts
```

また、api.tsの中身は以下のような形になっています。

```ts:api.ts
// Interfaceの定義などなど略

/**
 * HogehogeApi - object-oriented interface
 * @export
 * @class HogehogeApi
 * @extends {BaseAPI}
 */
export class HogehogeApi extends BaseAPI {
    /**
     * hogehoge
     * @summary hogehoge
     * @param {number} [limit] 
     * @param {number} [offset] 
     * @param {*} [options] Override http request option.
     * @throws {RequiredError}
     * @memberof HogehogeApi
     */
    public hogehogeIndex(limit?: number, offset?: number, options?: any) {
        return HogehogeApiFp(this.configuration).hogehogeIndex(limit, offset, options).then((request) => request(this.axios, this.basePath));
    }

    // 略
```

なお、`docker compose up`のたびに上書きされるのは鬱陶しかったので、
yamlを保存するディレクトリに専用のdocker-composeファイルを作り、
そちらを実行するのがマイベストでした。

##Nuxt.jsでの呼び出しの実装
今回はpluginファイルを作り、
contextから呼び出せるようにしました。


```ts:plugins/api.ts
import * as Axios from "~/types/client-axios";

export default function(
  { $axios, $config }: { $axios: any; $config: any },
  inject: any
): void {
  //BearerTokenやAPIのBasePathを設定する
  const config = (): Axios.Configuration => {
    const token = localStorage.getItem("auth._token.local");
    const basePath = $config.API_URL;
    const accessToken = token && typeof token === "string" ? token : "";

    return new Axios.Configuration({
      basePath,
      accessToken
    });
  };

  const api = {
    hogehogeApi: new Axios.hogehogeApi(config()),
    // こんな感じでClassごとに書き連ねていく
  };

  inject("api", api);
}
```

```js:nuxt.config.js
const config = {
  plugins: [
    "~/plugins/api",
  ],
};
```

これでVueファイルやVuexストアから自由に呼び出せるようになりました。

```vue:hogehoge/vue
<template>
  // 略
</template>

<script lang="ts">
import { Component, Vue } from "nuxt-property-decorator";
import * as Axios from "~/types/client-axios";

@Component
export default class Hogehoge extends Vue {
  hoges: Axios.HogehogeInterface[] = []; 
  limit:number = 20;
  page:number = 1;

  created(): void {
    this.load();
  }

  async load(): Promise<void> {
    const res = await (this as any).$api.hogehoge.hogehogeIndex(
      this.limit,
      (this.page - 1) * this.limit
    );
    this.hoges = [...this.hoges, ...res.data];
  }
```

# 参考

https://gift-tech.co.jp/articles/openapi-generator-typescript/