1
0

gin + oapi-codegen + Docker で構築するAPIサーバ

Posted at

本記事の目的

  • 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の中身のサンプルの実装例
  • GetSampleServerInterfaceにおいて実装すべきメソッドとして生成されたコードapi.gen.goに定義されている
  • 上記はもとより,パラメータやレスポンスとして使う型(GetSampleParamsSampleResponse,GetSample200JSONResponse)もapi.gen.goで定義されている
  • api.gen.goで自動生成された型を使った実装を守れば,OpenAPIで定義した通りのパラメータとレスポンスを持つAPIを実装可能

サーバを立ち上げる

# on project root
go mod tidy
go run ./api/

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
    

成果物

参考サイト

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0