本記事の目的
- oapi-codegenを使ってgin APIサーバ用のgo言語コードを生成する方法を学ぶ
- oapi-codegenの公式サンプルコードを必要最低限に単純化し,構成の本質的部分をハイライトする
- gin + oapi-codegenの実行環境をDockerで構築する
技術要素
- gin:GO言語ベースのWebフレームワーク.ルーティングやエラーハンドリング等のWebサーバとして必要な機能を備え,軽量なWebアプリを構築可能.APIサーバとして活用したり,静的ファイルのホスティングも可能
- oapi-codegen:OpenAPIのAPI仕様書から各種フレームワーク用のコードを生成できるジェネレータ.gin以外にもEchoなど主要なフレームワークに対応
構築物のディレクトリ構成のイメージ ※自動生成されるファイル等一部省略
完成物はこちらのリポジトリ参照
.
├─ api
| └─... #APIの実態のコードを配置
├─ config.yaml #oapi-codegen用の設定ファイル
├─ docker-compose.yaml #コンテナベースで開発したい場合に必要
├─ Dockerfile #コンテナベースで開発したい場合に必要
├─ generate.go
├─ Makefile
└─ openapi.yaml #OpenAPIのAPI仕様定義
構築手順
OpenAPIのコード仕様をyamlで定義する
まずはopenapi.yaml
に必要最低限のGETメソッドのみ定義
openapi.yaml
openapi: 3.0.1
info:
title: gin api sample
version: 1.0.0
paths:
'/sample':
get:
parameters:
- $ref: '#/components/parameters/sampleParam1'
responses:
'200':
description: Sampleの取得成功
content:
application/json:
schema:
$ref: '#/components/schemas/SampleArray'
'400':
description: 不正なリクエストです。
'401':
description: 認証エラーです。
components:
parameters:
sampleParam1:
in: query
name: param1
schema:
type: string
required: false
schemas:
SampleArray:
type: array
items:
$ref: '#/components/schemas/SampleResponse'
SampleResponse:
type: object
properties:
value:
type: string
oapi-codegenを使ってコードを生成する
oapi-codegenのインストール
基本的な使い方は,公式情報を参照のこと.goのコマンドが実行可能な環境で,下記のようにインストール可能.
go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest
oapi-codegenのコード生成用設定ファイルを用意
ファイル名はconfig.yaml
とする.今回はgin用のコードを生成するため,gin-server: true
と設定しておく.
config.yaml
package: main
generate:
models: true
embedded-spec: true
gin-server: true
strict-server: true
output-options:
skip-prune: true
output: ./api/api.gen.go
oapi-codegenのコード生成コマンドを実行
oapi-codegen -config config.yaml openapi.yaml
-
openapi/generate.go:4: running "oapi-codegen": exec: "oapi-codegen": executable file not found in $PATH
といったエラーになる場合,下記のようにGO PATHとGO ROOTを環境変数に定するとよいexport GOPATH=$HOME/go export PATH=$PATH:$GOPATH/bin
- コード生成が成功すれば,
api/api.gen.go
が自動生成される
APIの中身を実装する
まずは,go mod init
をプロジェクトのrootディレクトリで実行しておく
go mod init <your module name>
エントリーポイントとなるapi/main.go
を定義する
api/main.go
package main
import "github.com/gin-gonic/gin"
type SampleServer struct {
ServerId int
}
func main() {
r := gin.Default()
server := &SampleServer{
ServerId: 1, // Sample Value
}
RegisterHandlers(r, server)
r.Run() // listen and serve on 0.0.0.0:8080
}
- oapi-codegenの開発環境下でエントリーポイントを実装する際,
RegisterHandlers
を呼ぶことで,生成されたコード(api.gen.go
)を使うことができる -
api.gen.go
にはServerInterface
が定義されており,実装すべきメソッドが決められている.RegisterHandlers
の第2引数がServerInterface
となっており,自身で定義したServerInterface用のtypeを引き渡す - ServerInterface用のtype上で定義されているValue等は,API実装の各メソッドから共通して参照可能
- 今回のサンプルコードでいう
ServerId
を書きで実装するGETメソッドの内部処理から参照可能 - また,同サーバに別のメソッドを追加した際にも,同様に共通参照が可能
- 今回のサンプルコードでいう
APIの内部実装を行う
api/sample_get.go
package main
import (
"net/http"
"strconv"
"github.com/gin-gonic/gin"
"github.com/samber/lo"
)
func (server *SampleServer) GetSample(c *gin.Context, params GetSampleParams) {
responseArray := []SampleResponse{
{Value: params.Param1},
{Value: lo.ToPtr(strconv.Itoa(server.ServerId))},
}
var responseBody GetSample200JSONResponse = GetSample200JSONResponse(responseArray)
c.JSON(http.StatusOK, responseBody)
}
- 上記は,受け取ったパラメータと前述の
ServerInterface
から取り出したServerId
を含む配列を返す簡単なAPIの中身のサンプルの実装例 -
GetSample
はServerInterface
において実装すべきメソッドとして生成されたコードapi.gen.go
に定義されている - 上記はもとより,パラメータやレスポンスとして使う型(
GetSampleParams
やSampleResponse
,GetSample200JSONResponse
)もapi.gen.go
で定義されている -
api.gen.go
で自動生成された型を使った実装を守れば,OpenAPIで定義した通りのパラメータとレスポンスを持つAPIを実装可能
サーバを立ち上げる
# on project root
go mod tidy
go run ./api/
- GET http://localhost:8080/sample?param1=hage でアクセス
Dockerで動く環境に変更する
- 以下は必要に応じて任意
Makefileとgenerate.goを作成し,各種必要なコマンドを定義する
generate.go
package main
//go:generate oapi-codegen -config config.yaml openapi.yaml
Makefile
.PHONY: tidy
tidy:
go mod tidy
.PHONY: generate
generate:
go generate ./
Dockerfileおよびdocker-compose.yamlを作成する
- oapi-codegenのインストールおよび,各種go moduleのインストールも自動化
Dockerfile
FROM golang:1.22-alpine
RUN apk update && apk add --no-cache make
RUN mkdir /go/src/app/
WORKDIR /go/src/app/
COPY ./ /go/src/app/
RUN go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest
RUN make tidy
ENTRYPOINT [ "go", "run", "./api/" ]
docker-compose.yaml
version: "3"
services:
api:
build: ./
volumes:
- ./:/go/src/app/
ports:
- "8080:8080"
tty: true
コンテナ上でginを実行する
docker-compose build
docker-compose up -d
- OpenAPIの定義を変更し,コードを生成し直したい場合,コンテナの内部でコマンド実行可能
docker exec -it gin-api-sample-api-1 sh # in container make generate
成果物
参考サイト