Swaggerとは
OpenAPI Initialiveが提唱しているRestful APIの仕様記述に関する標準化を目指して作られたフォーマット、およびそのツール群です。yamlやjsonでAPI仕様を記述し、そのワークフローを支える幾つかのツールが提供されています。
ツール名 | 概要 |
---|---|
Swagger Core | Swaggerの仕様書をJava向けに読み書きするライブラリ |
Swagger Codegen | Swaggerの仕様書からクライアント/サーバのコードベースを生成するツール群、サードパーティー含め様々な言語向けに提供されています |
Swagger UI | Swaggerで記述されたAPI仕様をブラウザ側から確認するためのUI |
Swagger Editor | ブラウザベースで作成されたSwaggerの仕様を記述するためのエディタ |
詳しい仕様に関しては、公式サイトを参照ください。
http://swagger.io/
sample
Swaggerで記載されたAPIのサンプルを見てみましょう。
Sample: Petstore
GolangとSwagger
公式のSwagger CodegenではGolangの対応はありませんが、VMWare製OSSのgo-swagger/go-swagger
を利用することでGolangでもSwaggerの恩恵をうけることが可能です。
go-swaggerを使ってみる
まずはgo-swaggerをInstallしてください。今のところ、安定版ではなく、安定版ができ次第gopkg.in
で利用可能にするとのことでした。
$ go get -u github.com/go-swagger/go-swagger/cmd/swagger
上記をinstallすると、swagger
コマンドが使えるようになりますので、先ほどのサンプルを利用してAPIサーバを吐き出してみましょう。
$ cd $GOPATH/src/path/to/your_pj
#サーバサイドのコード生成
$ swagger generate server -f https://raw.githubusercontent.com/swagger-api/swagger-spec/master/examples/v2.0/json/petstore-expanded.json -a petstore
2015/12/13 18:11:42 rendered model template: Pet
2015/12/13 18:11:42 generated model Pet
2015/12/13 18:11:42 rendered model template: NewPet
2015/12/13 18:11:42 generated model NewPet
2015/12/13 18:11:42 rendered model template: Error
2015/12/13 18:11:42 generated model Error
2015/12/13 18:11:42 rendered handler template: petstore.FindPets
2015/12/13 18:11:42 generated handler petstore.FindPets
2015/12/13 18:11:42 rendered parameters template: petstore.FindPetsParameters
2015/12/13 18:11:49 generated parameters petstore.FindPetsParameters
2015/12/13 18:11:49 rendered responses template: petstore.FindPetsResponses
2015/12/13 18:11:49 generated responses petstore.FindPetsResponses
2015/12/13 18:11:49 rendered handler template: petstore.FindPetByID
2015/12/13 18:11:49 generated handler petstore.FindPetByID
2015/12/13 18:11:49 rendered parameters template: petstore.FindPetByIDParameters
2015/12/13 18:11:49 generated parameters petstore.FindPetByIDParameters
2015/12/13 18:11:49 rendered responses template: petstore.FindPetByIDResponses
2015/12/13 18:11:49 generated responses petstore.FindPetByIDResponses
2015/12/13 18:11:49 rendered handler template: petstore.AddPet
2015/12/13 18:11:49 generated handler petstore.AddPet
2015/12/13 18:11:49 rendered parameters template: petstore.AddPetParameters
2015/12/13 18:11:49 generated parameters petstore.AddPetParameters
2015/12/13 18:11:49 rendered responses template: petstore.AddPetResponses
2015/12/13 18:11:49 generated responses petstore.AddPetResponses
2015/12/13 18:11:49 rendered handler template: petstore.DeletePet
2015/12/13 18:11:49 generated handler petstore.DeletePet
2015/12/13 18:11:49 rendered parameters template: petstore.DeletePetParameters
2015/12/13 18:11:49 generated parameters petstore.DeletePetParameters
2015/12/13 18:11:49 rendered responses template: petstore.DeletePetResponses
2015/12/13 18:11:49 generated responses petstore.DeletePetResponses
2015/12/13 18:11:49 rendered builder template: petstore.SwaggerPetstore
2015/12/13 18:11:49 rendered embedded Swagger JSON template: server.SwaggerPetstore
2015/12/13 18:11:49 rendered configure api template: petstore.ConfigureSwaggerPetstore
2015/12/13 18:11:49 rendered doc template: petstore.SwaggerPetstore
2015/12/13 18:11:49 rendered main template: server.SwaggerPetstore
# client側のコード生成
$ swagger generate client -f https://raw.githubusercontent.com/swagger-api/swagger-spec/master/examples/v2.0/json/petstore-expanded.json -a petstore
2015/12/13 18:12:17 rendered model template: Pet
2015/12/13 18:12:17 generated model Pet
2015/12/13 18:12:17 rendered model template: NewPet
2015/12/13 18:12:17 generated model NewPet
2015/12/13 18:12:17 rendered model template: Error
2015/12/13 18:12:17 generated model Error
2015/12/13 18:12:17 rendered client parameters template: petstore.AddPetParameters
2015/12/13 18:12:20 rendered client responses template: petstore.AddPetResponses
2015/12/13 18:12:20 rendered client parameters template: petstore.DeletePetParameters
2015/12/13 18:12:20 rendered client responses template: petstore.DeletePetResponses
2015/12/13 18:12:20 rendered client parameters template: petstore.FindPetByIDParameters
2015/12/13 18:12:20 rendered client responses template: petstore.FindPetByIDResponses
2015/12/13 18:12:20 rendered client parameters template: petstore.FindPetsParameters
2015/12/13 18:12:20 rendered client responses template: petstore.FindPetsResponses
2015/12/13 18:12:20 rendered operation group client template: petstore.PetstoreClient
2015/12/13 18:12:20 rendered client embedded swagger JSON template: client.SwaggerPetstoreClient
2015/12/13 18:12:20 rendered client facade template: client.SwaggerPetstoreClient
上記でサーバ・クライアント双方のコードが生成されました。内容は下記です。
.
├── client
│ ├── petstore
│ │ ├── add_pet_parameters.go
│ │ ├── add_pet_responses.go
│ │ ├── delete_pet_parameters.go
│ │ ├── delete_pet_responses.go
│ │ ├── find_pet_by_id_parameters.go
│ │ ├── find_pet_by_id_responses.go
│ │ ├── find_pets_parameters.go
│ │ ├── find_pets_responses.go
│ │ └── petstore_client.go
│ ├── swagger_petstore_client.go
│ └── swagger_petstore_embedded_spec.go
├── cmd
│ └── swagger-petstore-server
│ ├── configure_swagger_petstore.go
│ ├── doc.go
│ ├── embedded_spec.go
│ └── main.go
├── models
│ ├── error.go
│ ├── new_pet.go
│ └── pet.go
└── restapi
└── petstore
├── add_pet.go
├── add_pet_parameters.go
├── add_pet_responses.go
├── delete_pet.go
├── delete_pet_parameters.go
├── delete_pet_responses.go
├── find_pet_by_id.go
├── find_pet_by_id_parameters.go
├── find_pet_by_id_responses.go
├── find_pets.go
├── find_pets_parameters.go
├── find_pets_responses.go
└── swagger_petstore_api.go
仕様をきっちりと記載さえしていればgodoc等も良しなに生成されているようでした。
この時点でcmdまで生成されているので、
$ go install <your swagger pj>/cmd/swagger-petstore-server
$ swagger-petstore-server
serving swagger petstore at http://127.0.0.1:62665
とするだけでサンプルのサーバが立ち上がる状態になっています。
また、その実装については、cmd/swagger-petstore-server/configure_swagger_petstore.go
を見ていただければ、実装すべき内容すぐわかるようになっています。
package main
import (
"github.com/go-swagger/go-swagger/errors"
"github.com/go-swagger/go-swagger/httpkit"
"github.com/go-swagger/go-swagger/httpkit/middleware"
"github.com/y-matsuwitter/swagger-sample/restapi/petstore"
)
// This file is safe to edit. Once it exists it will not be overwritten
func configureAPI(api *petstore.SwaggerPetstoreAPI) {
// configure the api here
api.ServeError = errors.ServeError
api.JSONConsumer = httpkit.JSONConsumer()
api.JSONProducer = httpkit.JSONProducer()
api.AddPetHandler = petstore.AddPetHandlerFunc(func(params petstore.AddPetParams) middleware.Responder {
return middleware.NotImplemented("operation addPet has not yet been implemented")
})
api.DeletePetHandler = petstore.DeletePetHandlerFunc(func(params petstore.DeletePetParams) middleware.Responder {
return middleware.NotImplemented("operation deletePet has not yet been implemented")
})
api.FindPetByIDHandler = petstore.FindPetByIDHandlerFunc(func(params petstore.FindPetByIDParams) middleware.Responder {
return middleware.NotImplemented("operation find pet by id has not yet been implemented")
})
api.FindPetsHandler = petstore.FindPetsHandlerFunc(func(params petstore.FindPetsParams) middleware.Responder {
return middleware.NotImplemented("operation findPets has not yet been implemented")
})
}
Clientを触ってみる
clientコードまで生成されているので、これを利用してAPIを叩いてみましょう。
package main
import (
"log"
apiclient "github.com/y-matsuwitter/swagger-sample/client"
"github.com/y-matsuwitter/swagger-sample/client/petstore"
)
func main() {
api := apiclient.Default.Petstore
res, err := api.FindPetByID(petstore.FindPetByIDParams{1})
log.Printf("%+v\n", res)
log.Println(err)
}
先ほどのsampleのjsonでの仕様書だとpetstore.swagger.io
をhostとして参照する仕様となっていたので、当然上記のサンプルはそちらのhostを叩きに行きます。
ちなみにこの投稿を書いている時点では上記ホストとsampleのjson仕様書の間に乖離があるようで、正常に動作しませんでした。(というかインターネット上に幾つか存在するpetstoreの仕様書が古い?)
最後に
Goでのマイクロサービス的な開発においてはこういったサーバ/クライアント間を統一的に記述できる仕組みからコードを生成してくれる仕組みはありがたいなと感じましたが、まだまだ使用してみた感じでは未完成な部分(日本語での記述で不具合起きるなど)が多く、今のところ自分にとってのswaggerはあくまで仕様書の記述にとどまるのではないかなと思いました。
あと、似たような領域ではjson-hyper-schemaがありますが、そちらとの比較もしてみたいなと思いました。