OpenAPI Generator CLI を使ってみた

RESTful な API を記述するためのフォーマットとして、OpenAPI というモノがある。以前は Swagger と呼ばれていて、Swagger 2.0 をベースに拡張・改称されたのが OpenAPI らしい。特に OpenAPI だから、Swagger だからという違いはないみたいで、名称は気にしなくて良さそう。

OpenAPI は YAML ないしは JSON 形式で API 仕様書を記述するのだが、それを HTML 化するツールとして Swagger UI というモノがある。

そして今回試すのは、YAML や JSON で書いた仕様書を基に、色々なプログラミング言語でのコードを自動生成してくれるツールである、OpenAPI Generator CLI である。

類似するツールとして Swagger CodeGen というツールもあるようだが、Swagger CodeGen の方がバグが多いと見聞きしたので、今回は OpenAPI Generator CLI を試してみた。

目次

セットアップ

OpenAPI Generator CLI は npm パッケージとしてインストールできる。

$ npm init -y
$ npm i -D @openapitools/openapi-generator-cli

以下のような package.json が用意できていれば OK。

{
  "name": "practice-openapi-generator",
  "private": true,
  "scripts": {
    "og": "openapi-generator-cli"
  },
  "devDependencies": {
    "@openapitools/openapi-generator-cli": "2.4.12"
  }
}

npm-run-scripts で og というエイリアス的な名前を用意したので、まずは以下のように実行してみる。

$ npm run og

Download 5.2.1 ...
Downloaded 5.2.1
Did set selected version to 5.2.1
Usage: openapi-generator-cli <command> [<args>]

Options:
  --custom-generator <generator>  Custom generator jar

Commands:
  version-manager                 Manage used / installed generator version
  author                          Utilities for authoring generators or customizing templates.
  batch                           Generate code in batch via external configs.
  config-help                     Config help for chosen lang
  generate [options]              Generate code with the specified generator.
  help                            Display help information about openapi-generator
  list                            Lists the available generators
  meta                            MetaGenerator. Generator for creating a new template set and configuration for Codegen.  The output will be based on the
                                  language you specify, and includes default templates to include.
  validate                        Validate specification
  version                         Show version information used in tooling

初回は裏で OpenAPI をダウンロードしているようだ。この CLI は OpenAPI Generator というツールをラップしているモノで、OpenAPI Generator は Java 製のようだ。node_modules/@openapitools/openapi-generator-cli/ 配下を見ると、5.2.1.jar がダウンロードされていた。

どんな言語のコードを出力できるのかは以下のように確認できる。

対応言語

$ npm run og list

The following generators are available:

CLIENT generators:
    - ada
    - android
    - apex
    - bash
    - c
    - clojure
    - cpp-qt-client
    - cpp-restsdk
    - cpp-tiny (beta)
    - cpp-tizen
    - cpp-ue4 (beta)
    - crystal (beta)
    - csharp
    - csharp-netcore
    - dart
    - dart-dio
    - dart-dio-next (experimental)
    - dart-jaguar
    - eiffel
    - elixir
    - elm
    - erlang-client
    - erlang-proper
    - go
    - groovy
    - haskell-http-client
    - java
    - java-micronaut-client (beta)
    - javascript
    - javascript-apollo (beta)
    - javascript-closure-angular
    - javascript-flowtyped
    - jaxrs-cxf-client
    - jmeter
    - k6 (beta)
    - kotlin
    - lua (beta)
    - nim (beta)
    - objc
    - ocaml
    - perl
    - php
    - php-dt (beta)
    - powershell (beta)
    - python (experimental)
    - python-legacy
    - r
    - ruby
    - rust
    - scala-akka
    - scala-gatling
    - scala-sttp (beta)
    - scalaz
    - swift5
    - typescript (experimental)
    - typescript-angular
    - typescript-aurelia
    - typescript-axios
    - typescript-fetch
    - typescript-inversify
    - typescript-jquery
    - typescript-nestjs (experimental)
    - typescript-node
    - typescript-redux-query
    - typescript-rxjs

SERVER generators:
    - ada-server
    - aspnetcore
    - cpp-pistache-server
    - cpp-qt-qhttpengine-server
    - cpp-restbed-server
    - csharp-nancyfx
    - erlang-server
    - fsharp-functions (beta)
    - fsharp-giraffe-server (beta)
    - go-echo-server (beta)
    - go-gin-server
    - go-server
    - graphql-nodejs-express-server
    - haskell
    - java-inflector
    - java-msf4j
    - java-pkmst
    - java-play-framework
    - java-undertow-server
    - java-vertx-web (beta)
    - jaxrs-cxf
    - jaxrs-cxf-cdi
    - jaxrs-cxf-extended
    - jaxrs-jersey
    - jaxrs-resteasy
    - jaxrs-resteasy-eap
    - jaxrs-spec
    - kotlin-server
    - kotlin-spring
    - kotlin-vertx (beta)
    - nodejs-express-server (beta)
    - php-laravel
    - php-lumen
    - php-mezzio-ph
    - php-slim4
    - php-symfony
    - python-aiohttp
    - python-blueplanet
    - python-fastapi (beta)
    - python-flask
    - ruby-on-rails
    - ruby-sinatra
    - rust-server
    - scala-akka-http-server (beta)
    - scala-finch
    - scala-lagom-server
    - scala-play-server
    - scalatra
    - spring

DOCUMENTATION generators:
    - asciidoc
    - cwiki
    - dynamic-html
    - html
    - html2
    - markdown (beta)
    - openapi
    - openapi-yaml
    - plantuml (beta)

SCHEMA generators:
    - avro-schema (beta)
    - graphql-schema
    - ktorm-schema (beta)
    - mysql-schema
    - protobuf-schema (beta)
    - wsdl-schema (beta)

CONFIG generators:
    - apache2

RoR (Ruby on Rails) やら Play Framework やら、サーバサイドの言語はもちろん、Angular などのようなクライアントサイド向けの言語・フレームワークにも対応しているようだ。

試しに実行してみた

試しに Angular 向けのコードを生成してみた。YAML ファイルは、OpenAPI Generator CLI が用意しているサンプルファイルをそのまま使ってみた。

$ npm run og -- generate -g typescript-angular -i https://raw.githubusercontent.com/OpenAPITools/openapi-generator-cli/master/examples/v2.0/yaml/petstore-minimal.yaml

[main] INFO  o.o.codegen.DefaultGenerator - Generating with dryRun=false
[main] INFO  o.o.c.ignore.CodegenIgnoreProcessor - No .openapi-generator-ignore file found.
[main] INFO  o.o.codegen.DefaultGenerator - OpenAPI Generator: typescript-angular (client)
[main] INFO  o.o.codegen.DefaultGenerator - Generator 'typescript-angular' is considered stable.
[main] INFO  o.o.c.l.AbstractTypeScriptClientCodegen - Hint: Environment variable 'TS_POST_PROCESS_FILE' (optional) not defined. E.g. to format the source code, please try 'export TS_POST_PROCESS_FILE="/usr/local/bin/prettier --write"' (Linux/Mac)
[main] INFO  o.o.c.l.AbstractTypeScriptClientCodegen - Note: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).
[main] INFO  o.o.c.l.TypeScriptAngularClientCodegen - generating code for Angular 11.0.0 ...
[main] INFO  o.o.c.l.TypeScriptAngularClientCodegen -   (you can select the angular version by setting the additionalProperty ngVersion)
[main] INFO  o.o.codegen.TemplateManager - writing file ./model/./pet.ts
[main] WARN  o.o.codegen.DefaultCodegen - Empty operationId found for path: get /pets. Renamed to auto-generated operationId: petsGet
[main] INFO  o.o.codegen.TemplateManager - writing file ./api/default.service.ts
[main] INFO  o.o.codegen.TemplateManager - writing file ./model/models.ts
[main] INFO  o.o.codegen.TemplateManager - writing file ./api/api.ts
[main] INFO  o.o.codegen.TemplateManager - writing file ./index.ts
[main] INFO  o.o.codegen.TemplateManager - writing file ./api.module.ts
[main] INFO  o.o.codegen.TemplateManager - writing file ./configuration.ts
[main] INFO  o.o.codegen.TemplateManager - writing file ./variables.ts
[main] INFO  o.o.codegen.TemplateManager - writing file ./encoder.ts
[main] INFO  o.o.codegen.TemplateManager - writing file /home/practice-openapi-generator/./.gitignore
[main] INFO  o.o.codegen.TemplateManager - writing file ./git_push.sh
[main] INFO  o.o.codegen.TemplateManager - writing file ./README.md
[main] INFO  o.o.codegen.TemplateManager - writing file /home/practice-openapi-generator/./.openapi-generator-ignore
[main] INFO  o.o.codegen.TemplateManager - writing file ./.openapi-generator/VERSION
[main] INFO  o.o.codegen.TemplateManager - writing file ./.openapi-generator/FILES
################################################################################
# Thanks for using OpenAPI Generator.                                          #
# Please consider donation to help us maintain this project 🙏                 #
# https://opencollective.com/openapi_generator/donate                          #
################################################################################

Angular プロジェクトとして完全に動作するようなコードではなく、API をコールする Service クラス関連が出力されていた。

確かに Angular 特有の HttpClient なんかを使ったコードは生成されていたが、恐ろしく可読性が悪く、どういう風に使ったらいいのか分からないようなコードだった。型定義の仕方も綺麗ではなく、コレを「TypeScript 対応」と言っていいのか悩ましいところだ。

OpenAPI 特有のユーティリティっぽいコードが結構生成されていた。この CLI ツールを使うと、API 仕様書とコードを同期してくれる機能があるらしいので、そのためのコードが散在しているようだ。Opinionated なプロジェクト・コードになりそうだし、依存関係が増えてちょっと嫌だな…。

続いて、Node.js Express サーバ向けのコードを生成させてみた。

$ npm run og -- generate -g nodejs-express-server -i https://raw.githubusercontent.com/OpenAPITools/openapi-generator-cli/master/examples/v2.0/yaml/petstore-minimal.yaml

[main] INFO  o.o.codegen.DefaultGenerator - Generating with dryRun=false
[main] INFO  o.o.c.ignore.CodegenIgnoreProcessor - No .openapi-generator-ignore file found.
[main] INFO  o.o.codegen.DefaultGenerator - OpenAPI Generator: nodejs-express-server (server)
[main] INFO  o.o.codegen.DefaultGenerator - Generator 'nodejs-express-server' is considered beta.
[main] INFO  o.o.c.l.NodeJSExpressServerCodegen - Environment variable JS_POST_PROCESS_FILE not defined so the JS code may not be properly formatted. To define it, try 'export JS_POST_PROCESS_FILE="/usr/local/bin/js-beautify -r -f"' (Linux/Mac)
[main] INFO  o.o.c.l.NodeJSExpressServerCodegen - NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).
[main] WARN  o.o.codegen.DefaultCodegen - Empty operationId found for path: GET /pets. Renamed to auto-generated operationId: petsGET
[main] INFO  o.o.codegen.TemplateManager - writing file ./services/DefaultService.js
[main] INFO  o.o.codegen.TemplateManager - writing file ./controllers/DefaultController.js
[main] INFO  o.o.codegen.TemplateManager - writing file ./api/openapi.yaml
[main] INFO  o.o.codegen.TemplateManager - writing file ./config.js
[main] INFO  o.o.codegen.TemplateManager - writing file ./expressServer.js
[main] INFO  o.o.codegen.TemplateManager - writing file ./index.js
[main] INFO  o.o.codegen.TemplateManager - writing file ./logger.js
[main] INFO  o.o.codegen.TemplateManager - writing file ./.eslintrc.json
[main] INFO  o.o.codegen.TemplateManager - writing file ./utils/openapiRouter.js
[main] INFO  o.o.codegen.TemplateManager - writing file ./controllers/index.js
[main] INFO  o.o.codegen.TemplateManager - writing file ./controllers/Controller.js
[main] INFO  o.o.codegen.TemplateManager - writing file ./services/index.js
[main] INFO  o.o.codegen.TemplateManager - writing file ./services/Service.js
[main] INFO  o.o.codegen.TemplateManager - writing file ./package.json
[main] INFO  o.o.codegen.TemplateManager - writing file ./README.md
[main] INFO  o.o.codegen.TemplateManager - writing file /home/practice-openapi-generator/./.openapi-generator-ignore
[main] INFO  o.o.codegen.TemplateManager - writing file ./.openapi-generator/VERSION
[main] INFO  o.o.codegen.TemplateManager - writing file ./.openapi-generator/FILES
################################################################################
# Thanks for using OpenAPI Generator.                                          #
# Please consider donation to help us maintain this project 🙏                 #
# https://opencollective.com/openapi_generator/donate                          #
################################################################################

コチラもなかなか酷い。なぜかロギングライブラリとして winston を使うようなコードを生成していたり、Express 本体に取り込まれていてもう不要になっている body-parser などが依存関係に入っていたり、テスティングツールである Chai や Mocha がインストールされたり。ファイル名もケースがバラバラで、スゲー扱いづらい。

全然使えん

OpenAPI Generator を開発されたのは日本人らしい。Swagger CodeGen などをベースにフォークして、コミュニティ主導で開発されているようだ。以下の開発者によるスライド解説によれば、自動生成されたコードはそのままにして、ロジックを書く時は継承・委譲する考えらしい。

設計思想はとても好き。コミュニティベースで開発されていて、現状の対応状況がまちまちなのも分かる。コレから発展していったらいいなと思うツールではある。

ただ、現状吐かれるコードを見る限り、このレベルのコードを自動生成されてもなぁ…コレをベースに開発したくはないな…という感じ。

デモや PoC のために、モックサーバを一気にガッと作っておしまい、というような場面なら使いどころはあるかもしれないが、API 仕様書とコードの同期を取って運用保守していくようなプロダクションレベルでは、まだちょっと使えないかな…。

なるべくコードを書かないようにしたい、とか、ドキュメントとコードの乖離を防ぎたい、とかいう思いは自分もあるので、こういうアプローチもあるのだなーという勉強にはなった。