おはようございます。最近仕事が全然進まず、一寸先は闇状態の社会人2年目の清田です。☔☔☔☔
前回の記事「俺的【OAS】との向き合い方 (爆速でOpenAPIと友達になろう)」が好評らしいので今回は続きを書くことにいたしました。🐈🐈🐈
この記事を読んでほしい人
- Go言語入門者 or 修行中の方
- OpenAPI Generator入門者 or 修行中の方
- Hello World
アジャイル系男子の日常
A「Spring bootよりGo Ginサーバーとかどう」 「キー(おっけーよ)」私 A「マイクロサービスにはもってこいだよね?」 「キー(なにそれおいしいの)」私
まぁ大体こんな感じで、アジャイル系男子の十八番にでもなっているのではないでしょうか。
Go言語嫌い大好きです。
Go Ginとは❔❔
Go言語のWebアプリケーションのフレームワークらしい。
そしてこちらを見てほしい。
おわかりいただけただろうか。
- MIT(ライセンス)
- 42.3k(star)
君に決めた。
自動生成手順📚
1. ファイル構成
└─openapi/ └─openapi.yml
2.openapi/openapi.yml
openapi: 3.0.1 info: title: title version: 1.0.0 paths: '/sample/point/{pathParam1}': get: tags: - api1 operationId: getSamplePoint parameters: - $ref: '#/components/parameters/pathParam1' - $ref: '#/components/parameters/queryParam1' responses: '200': description: Pointの取得成功 content: application/json: schema: $ref: '#/components/schemas/SampleArray' '400': description: 不正なリクエストです。 '401': description: 認証エラーです。 components: parameters: pathParam1: in: path name: param1 schema: type: string required: true queryParam1: in: query name: param2 schema: type: string required: false schemas: SampleArray: type: array items: $ref: '#/components/schemas/SampleResponse' SampleResponse: type: object properties: value: type: string
3.生成コマンド
$docker pull openapitools/openapi-generator-cli $docker run --rm -v ${PWD}/openapi:/local -v ${PWD}:/project openapitools/openapi-generator-cli generate -i /local/openapi.yml -g go-gin-server -o /project
4.★うわぁ。できたぁ。★
├─.openapi-generator-ignore ├─Dockerfile ├─main.go ├─.openapi-generator │ ├─FILES │ └─VERSION ├─api │ └─openapi.yml ├─go │ ├─api_api1.go │ ├─model_sample_response.go │ ├─README.md │ └─routers.go └─openapi └─openapi.yml
そして重要なことに気が付きます💦💦
Go言語に高階関数が見当たらない🔍
- 現状Goはジェネリクスがない?
- Go2とかいうバージョンが来たらジェネリクスが使える?
- それはいつなのか
GitHub - ahmetb/go-linq: .NET LINQ capabilities in Go
ジェネリクスがないと辛いと悟り、奇跡の出会いをした。
Go Generate との出会い
後半へ続く
新解体実行手順 ~Go2まで耐え抜く編~
解らないし高階関数ジェネレーターを適当に作っちゃおう(業務で作ったやつコピペ)🔨🔨
型変換も一行でやりたいよね。作っちゃお(業務で作ったやつコピペ)🔨🔨
1.ファイル構成
└─openapi/ ├─codegen <- New holder │ └─model.mustache <- New File └─openapi.yml
2. openapi/model.mustache
{{>partial_header}} package {{packageName}} {{#models}}{{#imports}} {{#-first}}import ( {{/-first}} "{{import}}"{{#-last}} ) {{/-last}}{{/imports}}{{#model}}{{#isEnum}}{{#description}}// {{{classname}}} : {{{description}}}{{/description}} type {{{name}}} {{^format}}{{dataType}}{{/format}}{{#format}}{{{format}}}{{/format}} // List of {{{name}}} const ( {{#allowableValues}} {{#enumVars}} {{{classname}}}_{{name}} {{{classname}}} = {{{value}}} {{/enumVars}} {{/allowableValues}} ){{/isEnum}}{{^isEnum}}{{#description}} // {{classname}} - {{{description}}}{{/description}} //go:generate stream-generator -type={{classname}} type {{classname}} struct { {{#vars}}{{#description}} // {{{description}}}{{/description}} {{name}} {{#isNullable}}*{{/isNullable}}{{{dataType}}} `json:"{{baseName}}{{^required}},omitempty{{/required}}"{{#vendorExtensions.x-go-custom-tag}} {{{.}}}{{/vendorExtensions.x-go-custom-tag}}` {{/vars}} }{{/isEnum}}{{/model}}{{/models}}
3.生成コマンドをもう一度
$docker pull openapitools/openapi-generator-cli $docker run --rm -v ${PWD}/openapi:/local -v ${PWD}:/project openapitools/openapi-generator-cli generate -i /local/openapi.yml -g go-gin-server -o /project -t /local/codegen
4. go generate
$go get -u github.com/optim-corp/stream-generator $go mod init sample go: creating new go.mod: module sample $cd go $go generate go: finding module for package github.com/gin-gonic/gin go: found github.com/gin-gonic/gin in github.com/gin-gonic/gin v1.6.3 2020/10/16 04:03:24 Generating Struct name: SampleResponse 2020/10/16 04:03:24 Scan Type Name. 2020/10/16 04:03:27 Scan Package Name. 2020/10/16 04:03:27 Generated C:\Users\optim\work\hatena-test\go\stream_sampleresponse.go
5.★うわぁ。できたぁ。2★
├─.openapi-generator-ignore ├─Dockerfile ├─main.go ├─.openapi-generator │ ├─FILES │ └─VERSION ├─api │ └─openapi.yml ├─go │ ├─api_api1.go │ ├─model_sample_response.go │ ├─README.md │ ├─routers.go │ └─stream_sampleresponse.go └─openapi/ ├─codegen │ └─model.mustache └─openapi.yml
とりあえず適当なレスポンス返してみる。🌶
main.go
package main import ( "log" sw "sample/go" ) func main() { log.Printf("Server started") router := sw.NewRouter() log.Fatal(router.Run(":8080")) }
go/api_api1.go
package openapi import ( "net/http" "github.com/gin-gonic/gin" ) // GetSamplePoint - func GetSamplePoint(c *gin.Context) { var ( entity = SampleResponseStreamOf() ) entity. AddAll( SampleResponse{"1"}, SampleResponse{"2"}, SampleResponse{"3"}, ) c.JSON(http.StatusOK, entity) }
実行👼
$go run main.go [GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached. [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production. - using env: export GIN_MODE=release - using code: gin.SetMode(gin.ReleaseMode) [GIN-debug] GET / --> sample/go.Index (3 handlers) [GIN-debug] GET /sample/point/:pathParam1 --> sample/go.GetSamplePoint (3 handlers) [GIN-debug] Listening and serving HTTP on :8080 [GIN] 2020/10/16 - 04:20:53 |?[97;42m 200 ?[0m| 0s | ::1 |?[97;44m GET ?[0m "/sample/point/hogehoge" [GIN] 2020/10/16 - 04:21:10 |?[97;42m 200 ?[0m| 0s | ::1 |?[97;44m GET ?[0m "/sample/point/hogehoge"
上が出たら成功!!!
確認👼👼
$curl --location --request GET 'http://localhost:8080/sample/point/hogehoge' [{"value":"1"},{"value":"2"},{"value":"3"}]
上が出たら成功!!!!!!!
そう僕たちは成し遂げたんだ。
大きな一歩を(思い込み)
Gitで管理する際のテンプレート
.gitignore
api go/model_* go/utils.go go/routers.go go.sum .idea/* .openapi-generator/* go/.openapi-generator/* **.exe
.openapi-generator-ignore
go/api_* go/README.md main.go api/* Dockerfile
docker-compose.yml
version: '3' services: openapi-generator: image: openapitools/openapi-generator-cli command: generate -i /local/openapi.yml -g go-gin-server -o /project -t /local/codegen volumes: - ./openapi:/local - .:/project
最後に
完全なサンプル
まとめ
今回はGo言語をたくさん書いても全然慣れないjava大好きっ子が、記事を書かせていただきました。 かなりざっくりとした内容ですので、どこかの誰かの役に立つことを祈っています。
オプティムはIT戦線の最前線希望の戦友エンジニアを募集しています❗