Myuon Corp. Advent Calendar 2016 3日目です。
Swagger を vagrant で建てた CentOS6.5 上で動かしてみた
Swagger を業務で使ってみようということになり、Vagrant 上に導入してみました。
Vagrant で CentOS6.5 を建てる方法については、割愛して Swagger とはなにか、導入の仕方と動かし方、扱い方をまとめてみようと思います。
Swagger とはなにか
Swagger とは Restful な API 仕様の記法と、記述するためのツール群です。
API 仕様を yaml か json で記述することができます。
何より特徴的なのが yaml, json の編集をブラウザ上で実行する事ができ、ライブプレビューで仕様書風なページが表示されることです。
また、記述したものをプレビューされている仕様書風なページ上で実行することができます。
実際に作成した仕様書を元に Server, Client のソースコードをジェネレートすることができるみたいですが、そこはまだ触れていないのでいずれまとめたいと思います。
建てた Vagrant の環境
今回、Swagger の Editor を Vagrant で建てようということになり、ミニマムな状態の CentOS (6.5) を建てました。
-
OS
$ cat /etc/redhat-release CentOS release 6.5 (Final) $ uname -a Linux swagger 2.6.32-431.el6.x86_64 #1 SMP Fri Nov 22 03:15:09 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
-
容量
$ df -h Filesystem Size Used Avail Use% Mounted on /dev/sda1 7.3G 1.6G 5.4G 24% / tmpfs 295M 0 295M 0% /dev/shm vagrant 465G 370G 96G 80% /vagrant
Swagger の導入
Swagger には node.js 製のもの、 javascript 製のものがあるようです。
まずは、エディタを動かしたいので swagger-editor を導入します。
必要なものは以下のものです。
- nodejs
- npm
- wget
- http-server
- swagger-editor
上の3つは yum でインストールしちゃいます。
$ sudo yum install -y nodejs
$ sudo yum install -y npm
$ sudo yum install -y wget
次の、 http-server は node.js 製の HTTP サーバです。
npm でインストールします。
$ npm install -g http-server
単に swagger-editor 内の index.html が HTTP サーバ上で動作すれば良いので、手元に rails があれば public の下に swagger-editor を置いても動作します。
とりあえず動かすのが目的であれば、他のもので代用しても問題ありません。
最後に、swagger-editor の取得です。
wget でソースコードの zip をダウンロードします。
$ wget https://github.com/swagger-api/swagger-editor/releases/download/v2.10.4/swagger-editor.zip
ダウンロードしたものは解凍しましょう。
$ unzip ./swagger-editor.zip
Swagger の動かし方
ようやく、swagger-editor を動かす時が来ました。
http-server swagger-editor
実行すると、次のような出力が得られます。
Starting up http-server, serving swagger-editor
Available on:
http://127.0.0.1:8081
http://10.0.2.15:8081
http://192.168.33.52:8081
Hit CTRL-C to stop the server
ブラウザでアクセスすると見事エディタが起動します。
導入はすごく簡単ですね。
Swagger の扱い方
Swagger の扱い方として、次のものを順にまとめます。
- 書き方
- Type
- プロジェクト
書き方
swagger-editor を起動してアクセスすると、まずエディタにはサンプルの yaml が貼り付けられていて、おおよその書き方はそのサンプルのコメントで分かるようになっています。
また、エディタのステータスバーの File
> Open Example...
から別のサンプルを開くこともできるので、不足分はそちらで補うこともできそうです。
書き方の解説は yaml 形式で、例に上げるサンプルを petstore_full.yaml
としてまとめます。
-
構成
ルート階層は次の表のようになっています。
key 型 用途 swagger string swagger のバージョン info object API の情報 host string API のホスト basePath string API のベースパス schemes array 使用可能なスキームのリスト paths object API のパスのリスト securityDefinitions: object 認証などのセキュリティの定義 definitions object モデルのリスト それぞれの解説をします。
swagger はそのまんまですね。
サンプルでは次のようになっています。swagger: "2.0"
info は次のような情報を持ちます。
key 型 用途 description string API がどういうものなのかの説明文 version string API のバージョン title string API のタイトル (プロジェクト名) termsOfService string 利用規約ページ contact object name
をキーとした連絡先license object name
をキーとしたライセンス名、url
をキーとしたライセンス条文のページのリンクミニマムで設定するのであれば、
description
,title
,version
だけで良さそうです。
サンプルでは次のようになっています。info: description: | This is a sample server Petstore server. [Learn about Swagger](http://swagger.io) or join the IRC channel `#swagger` on irc.freenode.net. For this sample, you can use the api key `special-key` to test the authorization filters version: "1.0.0" title: Swagger Petstore termsOfService: http://helloreverb.com/terms/ contact: name: apiteam@swagger.io license: name: Apache 2.0 url: http://www.apache.org/licenses/LICENSE-2.0.html
host , basePath はそのまんまですね。
サンプルでは次のようになっています。host: petstore.swagger.io basePath: /v2
schemes は利用可能なスキームを列挙します。
サンプルでは次のようになっています。schemes: - http
これを増やすと、プレビューページで実行する際のスキームの選択肢が増えます。
paths は一番重要なところです。
次のような情報を持ちます。
※ 階層が深くなるので.
で連結して階層を表現します。key 型 用途 /pets/{petId} string リソースへのパス /pets/{petId}.get object /pets/{petId}.get.tags array Swagger の仕様書上でフィルタするためのタグ /pets/{petId}.get.summary string エンドポイントに対する概要 /pets/{petId}.get.description string エンドポイントに対する説明 /pets/{petId}.get.operationId string operationId FIXME /pets/{petId}.get.produces array 出力可能なコンテンツタイプのリスト /pets/{petId}.get.parameters array パラメータの定義のリスト /pets/{petId}.get.parameters[].in string パラメータの配置先 path
か `query/pets/{petId}.get.parameters[].name string パラメータ名 /pets/{petId}.get.parameters[].description string パラメータの説明 /pets/{petId}.get.parameters[].requied boolean 必須かどうか /pets/{petId}.get.parameters[].type string 型 /pets/{petId}.get.parameters[].format string 型のフォーマット /pets/{petId}.get.response object レスポンスの定義 /pets/{petId}.get.response."404" object 404 レスポンスの定義 /pets/{petId}.get.response."404".description string 404 レスポンスの説明 /pets/{petId}.get.response."200" object 200 レスポンスの定義 /pets/{petId}.get.response."200".description string 200 レスポンスの説明 /pets/{petId}.get.response."200".schema object 200 レスポンスのボディ /pets/{petId}.get.security array セキュリティの定義 /pets/{petId}.get.security.api_key array? [] を指定すると未指定にできる FIXME /pets/{petId}.get.security.petstore_auth array 後述の securityDefinitions
への参照となるkey
/pets/{petId}
のように{}
を使用することでプレースホルダにすることができます。get
の部分はpost
とすることで POST の定義を作成できます。tags
は、Swagger のプレビューページでフィルタリングするためのもののようです。
summary
,tags
,produces
はオプショナルです。
produces
はルート階層に配置することも可能です。parameters
に定義するオブジェクトはin
キーに対してpath
を与えると、path で設置したプレースホルダに対応します。
in
キーに対してquery
を与えると、?parameter.key=
のようなURLのクエリ部に対応します。
parameters
のtype
は後述します。response
の子要素のキーは HTTP ステータスコードかdefault
という文字列を指定する必要があります。
5xx
とかできないのはちょっと不便に思いました。しかも、default
って、、、。security
の子要素は、後述のsecurityDefinitions
を参照することができるようです。サンプルでは次のようになっています。
/pets/{petId}: get: tags: - pet summary: Find pet by ID description: Returns a pet when ID < 10. ID > 10 or nonintegers will simulate API error conditions operationId: getPetById produces: - application/json - application/xml parameters: - in: path name: petId description: ID of pet that needs to be fetched required: true type: integer format: int64 responses: "404": description: Pet not found "200": description: successful operation schema: $ref: "#/definitions/Pet" "400": description: Invalid ID supplied security: - api_key: [] - petstore_auth: - write_pets - read_pets
securityDefinitions は次のような情報を持ちます。
key 型 用途 api_key object api_key オブジェクトの定義 api_key.type string FIXME api_key.name string FIXME api_key.in string FIXME petstore_auth object FIXME petstore_auth.type string 認証方式 petstore_auth.authorizationUrl string 認証を行うページへのURL petstore_auth.flow string FIXME petstore_auth.scopes array FIXME 全体的に未確認なので、早急に確認してまとめたいと思います。
サンプルでは次のようになっています。securityDefinitions: api_key: type: apiKey name: api_key in: header petstore_auth: type: oauth2 authorizationUrl: http://petstore.swagger.io/api/oauth/dialog flow: implicit scopes: write_pets: modify pets in your account read_pets: read your pets
definitions はいわゆる モデル の定義です。
次のような情報を持ちます。key 型 用途 Pet object Pet オブジェクトの定義 Pet.type string Pet オブジェクトの型 Pet.required array Pet オブジェクトのプロパティの内必須なもののキーのリスト Pet.properties object Pet オブジェクトのプロパティの定義 Pet.properties.id object Pet オブジェクトのプロパティ id
の定義Pet.properties.id.type string Pet オブジェクトのプロパティ id
の型Pet.properties.id.format string Pet オブジェクトのプロパティ id
のフォーマットPet.properties.name string Pet オブジェクトのプロパティ name
の定義Pet.properties.name string Pet オブジェクトのプロパティ name
の定義Pet.properties.name.type string Pet オブジェクトのプロパティ name
の型Pet.properties.name.example string Pet オブジェクトのプロパティ name
の例ルート階層のキー名がモデル名になります。
具体的なところはtype
の説明を参照してください。サンプルでは次のようになっています。
Pet: type: object required: - name - photoUrls properties: id: type: integer format: int64 category: $ref: "#/definitions/Category" name: type: string example: doggie photoUrls: type: array items: type: string tags: type: array items: $ref: "#/definitions/Tag" status: type: string description: pet status in the store
-
Type
type には 次のものがあります。
- string
- float
- boolean
- array<?>
- integer
- object
string
,float
,boolean
,array
は特に解説することはありません。
上の解説の中には出てきませんでしたがfloat
も利用できます。
Yaml: types を参照してください。
※ rails で yaml を利用する分には気づきませんでしたが、 キーに対して子要素もない、設定値もないと言うのは許可されないようです。integer
にはformat
がセットになります。
format
をキーとして、int32
やint64
を指定する事ができます。object
はいわゆるハッシュです。いずれもキーを
$ref
とすることで、設定値を参照にすることができます。
この時の設定値は例えば"#/definitions/Pet"
のようになります。 -
プロジェクト
swagger を npm でインストールすると、
swagger
コマンドが利用できるようになります。この
swagger
コマンドにはproject
という、サブコマンドがあり、次の機能があります。Commands: create [options] [name] Create a folder containing a Swagger project start [options] [directory] Start the project in this or the specified directory verify [options] [directory] Verify that the project is correct (swagger, config, etc) edit [options] [directory] open Swagger editor for this project or the specified project directory open [directory] open browser as client to the project test [options] [directory_or_file] Run project tests generate-test [options] [directory] Generate the test template
肝となる
edit
は、どうもブラウザを起動して swagger-editor を開くもののようで、Vagrant で建てた VM では次のようなエラーが出ました。$ swagger project edit Starting Swagger Editor. Opening browser to: http://127.0.0.1:43390/#/edit { [Error: Command failed: /bin/sh: xdg-open: command not found ] killed: false, code: 127, signal: null }
いずれ解決してやりたいと思います。
それはさておき、ひとまずプロジェクトを作ります。次のコマンドで、プロジェクトを作成することができます。
swagger project create <プロジェクト名>
このコマンドを実行すると、次のような内容物を持つディレクトリが生成されます。
$ ls -l total 28 drwxr-xr-x 6 vagrant vagrant 4096 Dec 2 05:11 api -rw-r--r-- 1 vagrant vagrant 546 Dec 2 05:11 app.js drwxr-xr-x 2 vagrant vagrant 4096 Dec 2 05:11 config drwxrwxr-x 6 vagrant vagrant 4096 Dec 2 05:11 node_modules -rw-r--r-- 1 vagrant vagrant 425 Dec 2 05:11 package.json -rw-r--r-- 1 vagrant vagrant 31 Dec 2 05:11 README.md drwxr-xr-x 3 vagrant vagrant 4096 Dec 2 05:11 test
作成した swagger の定義ファイルは、
./api/swagger/
に配置します。Git 管理に載せる場合は、まとまっていたほうがスッキリするのでひとまずこのプロジェクトにしたもので扱う予定です。
もっといい方法がわかったらまとめたいと思います。また、他の機能はまだ試せていないので、そちらも試してまとめる予定です。
まとめ
実際、swagger-editor は日本語に弱いらしく、変な入力になることが多々あります。
あまり使いやすいとは言いづらいですが、候補も出ますし、たまにテキスト全体をカット&ペーストすればエラーもちゃんと出してくれます。
プレビューのページはモデルあたりは非常に見難く、そのまま PDF化すれば納品物にできるぜというものではありません。
ドキュメント化という点では Swagger2Markup などの別のツールもあるみたいですが、まだ触れていないので色々試してまとめていきたいと思います。
それと、こういうものこそ Docker と連携しやすいっぽいですね。
まぁ、何にしろ yaml で記述できる手軽さは良いですね。
ちゃんとメンテされるドキュメンテーションへの第一歩ということで。
明日は @nullpopon@github さんです。
どんなことを記事にしてくれるのか楽しみです。