OpenAPI
OpenAPI、正確にはOpenAPI SpecificationはREST APIの定義を記述するための規格です。
つまり、APIサーバがどのような挙動をするのかを記した設計書のようなものです。
2015年末まではSwagger Specificationと呼ばれていたので、こちらの方を知っている方もいるかもしれません。
さて、これがあると何が嬉しいかというといろいろ嬉しいことがあるのですが、主なメリットは次の3点です。
- APIを決まったフォーマットで規定できる
- そのままAPIドキュメントになる
- API定義からサーバやクライアントのコード生成ができる
Swagger時代からSwagger Specificationに関連したツールが出回っており、ツールを利用することで手軽に上記のメリットを享受できるようになっています。
メリット | 代表的なツール |
---|---|
APIを決まったフォーマットで規定できる | OpenAPI Specification Swagger Specification |
APIドキュメントになる | Swagger UI |
コード生成ができる | OpenAPI generator Swagger Codegen |
他にもOpenAPI Specificationを利用した様々なツールが作成されているので、気になる方は公式レポジトリのリストを覗いてみてください。
https://github.com/OAI/OpenAPI-Specification/blob/master/IMPLEMENTATIONS.md
本稿ではSwaggerとOpenAPIやバージョン2と3の話はOpenAPI generatorの話から脱線してしまうため触れないこととし、OpenAPI v3.0を対象とします。
OpenAPI Specification
JSONまたはYAML形式でAPIのrequest endpointやparameter, responseを記述することができます。
例えば、次のようなYAMLファイルを記述することで、APIが /pets
というend pointを持つことや、200 OK
のレスポンスにid
とname
を持つリストがjson形式で返ってくることがわかります。
openapi: "3.0.0"
info:
version: 1.0.0
title: Swagger Petstore
license:
name: MIT
servers:
- url: http://petstore.swagger.io/v1
paths:
/pets:
get:
summary: List all pets
operationId: listPets
tags:
- pets
parameters:
- name: limit
in: query
description: How many items to return at one time (max 100)
required: false
schema:
type: integer
format: int32
responses:
'200':
description: A paged array of pets
headers:
x-next:
description: A link to the next page of responses
schema:
type: string
content:
application/json:
schema:
$ref: "#/components/schemas/Pets"
default:
description: unexpected error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
components:
schemas:
Pet:
required:
- id
- name
properties:
id:
type: integer
format: int64
name:
type: string
tag:
type: string
Pets:
type: array
items:
$ref: "#/components/schemas/Pet"
Error:
required:
- code
- message
properties:
code:
type: integer
format: int32
message:
type: string
このYAMLは こちらのsampleを簡略化したもの。
OpenAPI generator
OpenAPI generatorは先程述べたメリットの3番目、OpenAPI Specificationを元にクライアントやサーバのコードを生成するソフトウェアです。
もともとSwaggerの時代からSwagger CodeGenとしてコード生成のツールは提供されており今でも利用可能なのですが、どうも開発者同士で反りが合わなかったらしくコミュニティ主導のツールとしてOpenAPI Specificationは誕生しました。
OpenAPI generatorの開発者がそのあたりの経緯を書いています。(日本語)
https://ackintosh.github.io/blog/2018/05/12/openapi-generator/
私が2018年9月頃にSwagger CodeGenを触った感触でやはりSwagger CodeGenはOpenAPI Specification v3.0への対応が遅れていると感じたため、2019年3月現時点でもOASv3.0を利用する場合は様々な言語に対応しているOpenAPI generatorを利用するのが良さそうです。
環境
利用方法はいくつかあるのですが、今回はdocker imageを利用します。
macでDocker Desktop for Macを利用しています。
$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.14.3
BuildVersion: 18D109
$ docker --version
Docker version 18.09.1, build 4c52b90
生成したコードを出力する場所を作っておきます。
また、先程の簡略化petstore.yamlをカレントディレクトリにおいておきます。
$ mkdir openapi_generator_sample
$ cd openapi_generator_sample/
$ cp /somewhere/petstore.yaml ./
コード生成
こちらにかかれている通り、次のコマンドで Flask/Python のサーバサイドコードが生成されます。
$ GENERATOR=python-flask
$ docker run --rm -v ${PWD}:/local openapitools/openapi-generator-cli generate -i /local/petstore.yaml -g ${GENERATOR} -o /local/out/${GENERATOR}
長いですが、dockerでopenapitools/openapi-generator-cli
イメージのgenerateコマンドを呼び出して、次のオプションを渡しているだけです。
オプション | 意味 |
---|---|
-g |
生成するコードの種類を指定 |
-i |
OpenAPI Specificationのyamlファイルを指定 |
-o |
出力する場所を指定 |
上記コードを実行すると out/python-flask
フォルダの中にFlaskのコード(ボイラープレート/scaffold)が生成されます。
$ tree out/python-flask/
out/python-flask/
├── Dockerfile
├── README.md
├── git_push.sh
├── openapi_server
│ ├── __init__.py
│ ├── __main__.py
│ ├── controllers
│ │ ├── __init__.py
│ │ ├── pets_controller.py
│ │ └── security_controller_.py
│ ├── encoder.py
│ ├── models
│ │ ├── __init__.py
│ │ ├── base_model_.py
│ │ ├── error.py
│ │ └── pet.py
│ ├── openapi
│ │ └── openapi.yaml
│ ├── test
│ │ ├── __init__.py
│ │ └── test_pets_controller.py
│ └── util.py
├── requirements.txt
├── setup.py
├── test-requirements.txt
└── tox.ini
5 directories, 21 files
対応言語
別の言語でもGENERATOR部分を変えることによって簡単に同等のコードを生成できます。例えばRuby on Railsの場合は次のようにします。
$ GENERATOR=ruby-on-rails
$ docker run --rm -v ${PWD}:/local openapitools/openapi-generator-cli generate -i /local/petstore.yaml -g ${GENERATOR} -o /local/out/${GENERATOR}
$ tree out/ruby-on-rails/
out/ruby-on-rails/
├── Dockerfile
├── Gemfile
├── README.md
├── Rakefile
├── app
│ ├── channels
│ │ └── application_cable
│ │ ├── channel.rb
│ │ └── connection.rb
│ ├── controllers
│ │ ├── application_controller.rb
│ │ └── pets_controller.rb
│ ├── jobs
│ │ └── application_job.rb
│ ├── mailers
│ │ └── application_mailer.rb
│ ├── models
│ │ ├── application_record.rb
│ │ ├── error.rb
│ │ └── pet.rb
│ └── views
│ └── layouts
│ ├── mailer.html.erb
│ └── mailer.text.erb
├── bin
│ ├── bundle
│ ├── rails
│ ├── rake
│ ├── setup
│ └── update
├── config
│ ├── application.rb
│ ├── boot.rb
│ ├── cable.yml
│ ├── database.yml
│ ├── environment.rb
│ ├── environments
│ │ ├── development.rb
│ │ └── production.rb
│ ├── initializers
│ │ ├── active_record_belongs_to_required_by_default.rb
│ │ ├── application_controller_renderer.rb
│ │ ├── backtrace_silencers.rb
│ │ ├── callback_terminator.rb
│ │ ├── cors.rb
│ │ ├── filter_parameter_logging.rb
│ │ ├── inflections.rb
│ │ ├── mime_types.rb
│ │ ├── ssl_options.rb
│ │ └── to_time_preserves_timezone.rb
│ ├── locales
│ │ └── en.yml
│ ├── puma.rb
│ ├── routes.rb
│ ├── secrets.yml
│ └── spring.rb
├── config.ru
├── db
│ ├── migrate
│ │ └── 0_init_tables.rb
│ ├── schema.rb
│ └── seeds.rb
├── docker-entrypoint.sh
├── lib
│ └── tasks
├── log
├── public
│ ├── 404.html
│ ├── 422.html
│ ├── 500.html
│ ├── apple-touch-icon-precomposed.png
│ ├── apple-touch-icon.png
│ ├── favicon.ico
│ └── robots.txt
├── test
│ └── test_helper.rb
├── tmp
│ ├── cache
│ ├── pids
│ ├── restart.txt
│ └── sockets
└── vendor
26 directories, 56 files
GENERATORに入れる値は次のコマンドで調べることができます。
Django等対応していないフレームワークもありますが、結構充実しています。
$ docker run --rm openapitools/openapi-generator-cli list
api-generator-cli list
The following generators are available:
CLIENT generators:
- ada
- android
- apex
- bash
- c
- clojure
- cpp-qt5-client
- cpp-restsdk
- cpp-tizen
- csharp
- csharp-dotnet2
- csharp-netcore
- dart
- dart-jaguar
- eiffel
- elixir
- elm
- erlang-client
- erlang-proper
- flash
- go
- groovy
- haskell-http-client
- java
- javascript
- javascript-closure-angular
- javascript-flowtyped
- jaxrs-cxf-client
- jmeter
- kotlin
- lua
- objc
- perl
- php
- powershell
- python
- r
- ruby
- rust
- scala-akka
- scala-gatling
- scala-httpclient-deprecated
- scalaz
- swift2-deprecated
- swift3-deprecated
- swift4
- typescript-angular
- typescript-angularjs
- typescript-aurelia
- typescript-axios
- typescript-fetch
- typescript-inversify
- typescript-jquery
- typescript-node
- typescript-rxjs
SERVER generators:
- ada-server
- aspnetcore
- cpp-pistache-server
- cpp-qt5-qhttpengine-server
- cpp-restbed-server
- csharp-nancyfx
- erlang-server
- go-gin-server
- go-server
- graphql-nodejs-express-server
- haskell
- java-inflector
- java-msf4j
- java-pkmst
- java-play-framework
- java-undertow-server
- java-vertx
- jaxrs-cxf
- jaxrs-cxf-cdi
- jaxrs-cxf-extended
- jaxrs-jersey
- jaxrs-resteasy
- jaxrs-resteasy-eap
- jaxrs-spec
- kotlin-server
- kotlin-spring
- nodejs-server
- php-laravel
- php-lumen
- php-silex
- php-slim
- php-symfony
- php-ze-ph
- python-aiohttp
- python-blueplanet
- python-flask
- ruby-on-rails
- ruby-sinatra
- rust-server
- scala-finch
- scala-lagom-server
- scalatra
- spring
DOCUMENTATION generators:
- cwiki
- dynamic-html
- html
- html2
- openapi
- openapi-yaml
SCHEMA generators:
- mysql-schema
CONFIG generators:
- apache2
- graphql-schema
サーバを動かしてみる
生成したコードはすぐに起動できるようになっています。
試しに生成したばかりのFlaskを起動してみます。
$ cd out/python-flask/
$ docker build -t openapi_server .
$ docker run -p 8080:8080 openapi_server
これで http://localhost:8080/v1/pets にアクセスして次のようなレスポンスが得られたら成功です。
その先
OpenAPI generatorで生成できるサーバサイドのコードはロジックが記述されていません。API定義から生成したので当たり前ですね。そのため、実際にAPIサーバとして利用するためにはこのあとにロジックを書く必要があります。
しかし自動生成したコードにロジックを書くと、API定義に変更があったときにコード側が自動生成で追随できなくなってしまいます。この問題に関する話題はまた別の記事で書きます。
まとめ
今回はOpenAPIの周囲のツールのうち、OpenAPI generatorを触ってみました。
OpenAPI generatorではAPI定義から様々なAPIサーバの雛形を簡単に生成することができました。
API Specificationを先に書くことによって、フロントエンドとサーバサイドの同時開発ができる、コードの雛形の生成ができる、APIドキュメントを別途用意・メンテする必要がなくなるというメリットが享受できます。
個人的にはpetstore.yaml
から雛形だけ作成して色々なWebフレームワークの実装の練習に利用しようかなと考えています。
参考
開発者の方の解説。すごくわかりやすかったです。
https://speakerdeck.com/akihito_nakano/gunmaweb34