Edited at
GoDay 12

go-swaggerの紹介

More than 3 years have passed since last update.


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がありますが、そちらとの比較もしてみたいなと思いました。