Nuxt.js
TypeScript
OpenAPI
概要
- WebAPIの設計書としてOpenAPI Specification(以下、OpenAPI Spec)を採用する
- フロントエンド、バックエンド共にOpenAPI Specからソースコードを自動生成する
- 本記事はフロントエンドのみを対象とする
- 自動生成したAPIクライアントをNuxt.jsのpluginsに組み込んでvueファイルから参照する
- TypeScriptで型安全に開発する
前提条件
OpenAPI Spec
周辺ツールの対応状況を鑑みてv3.0.0を前提とする。
Docker
OpenAPI Specからソースコードを自動生成ツールとしてDocker版のOpenAPI Generatorを使用するため。 CLIやGradleプラグイン等あるが、グローバルな環境を汚さずにフロントエンド、バックエンド共に使用するツールを揃えられるのでDocker版を使用する。
openapitools/openapi-generator-cli
Node.js / Yarn
フロントエンドの開発においてはもはやインストールされていて当たり前なものなので割愛。
Nuxt.js
Nuxt3は2022/8/4時点ではRelease CandidateなのでNuxt2を前提とする。
事前準備
プロジェクト作成
公式 の手順に従い、適当なプロジェクトを作成。
$ yarn create nuxt-app open-api-sample
yarn create v1.22.18
[1/4] 🔍 Resolving packages...
[2/4] 🚚 Fetching packages...
[3/4] 🔗 Linking dependencies...
[4/4] 🔨 Building fresh packages...
warning Your current version of Yarn is out of date. The latest version is "1.22.19", while you're on "1.22.18".
info To upgrade, run the following command:
$ curl --compressed -o- -L https://yarnpkg.com/install.sh | bash
success Installed "create-nuxt-app@4.0.0" with binaries:
- create-nuxt-app
create-nuxt-app v4.0.0
✨ Generating Nuxt.js project in open-api-sample
? Project name: open-api-sample
? Programming language: TypeScript
? Package manager: Yarn
? UI framework: None
? Nuxt.js modules: Axios - Promise based HTTP client
? Linting tools: (Press <space> to select, <a> to toggle all, <i> to invert selection)
? Testing framework: None
? Rendering mode: Universal (SSR / SSG)
? Deployment target: Server (Node.js hosting)
? Development tools: (Press <space> to select, <a> to toggle all, <i> to invert selection)
? What is your GitHub username? i-zacky
? Version control system: None
🎉 Successfully created project open-api-sample
To get started:
cd open-api-sample
yarn dev
To build & start for production:
cd open-api-sample
yarn build
yarn start
For TypeScript users.
See : https://typescript.nuxtjs.org/cookbook/components/
✨ Done in 144.63s.
APIクライアントの自動生成
OpenAPI Specは 公式のサンプル を使用。
docker run --rm \
-v "${PWD}/openapi:/out" \
openapitools/openapi-generator-cli:v6.0.1 generate \
--generator-name typescript-axios \
--input-spec https://raw.githubusercontent.com/openapitools/openapi-generator/master/modules/openapi-generator/src/test/resources/3_0/petstore.yaml \
--output /out \
--api-package api \
--model-package model \
--generate-alias-as-model \
--additional-properties supportsES6=true \
--additional-properties withInterfaces=true \
--additional-properties withSeparateModelsAndApi=true
本題
pluginsの実装
ポイントは2つ。
apiFactory
でOpenAPI Generatorによって自動生成されたAPIクライアントを束ねていく- OpenAPI Specに追従して
return
ブロックを更新していく - 自動生成されたAPIクライアントにnuxt/axiosのAxiosインスタンスをインジェクションする
- OpenAPI Specに追従して
declare module
で型定義をする
import { Context, Inject } from '@nuxt/types/app'
import * as openapi from '@/openapi/index'
const apiFactory = (context: Context) => {
const config = () => {
const basePath = process.env.API_BASE_URL
return new openapi.Configuration({
basePath,
})
}
return {
PetApi: new openapi.PetApi(config(), '', context.$axios),
StoreApi: new openapi.StoreApi(config(), '', context.$axios),
UserApi: new openapi.UserApi(config(), '', context.$axios),
}
}
export default (context: Context, inject: Inject) => {
inject('api', apiFactory(context))
}
declare module 'vue/types/vue' {
interface Vue {
$api: ReturnType<typeof apiFactory>
}
}
pluginsの有効化
export default {
// plugins以外は省略
plugins: ['~/plugins/api']
}
コンポーネントから呼び出してみる
<template>
<Tutorial/>
</template>
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
name: 'IndexPage',
methods: {
async getPetById(id: number) {
// this.$api.XXX.YYYでOpenAPI Generatorで自動生成したAPIクライアントを呼び出せる
await this.$api.PetApi.getPetById(id)
}
}
})
</script>