Go API に Swagger を追加する
コードの注釈から自動生成されたOpenAPIドキュメント
APIドキュメンテーションは、現代のアプリケーションにおいて非常に重要です。Go API Swagger(OpenAPI)は、業界標準となっています。Go開発者にとって、swaggoはコードの注釈から包括的なAPIドキュメンテーションを生成するための洗練されたソリューションを提供します。
この素晴らしい画像は、AIモデル Flux 1 devによって生成されました。
Go APIにおいてSwaggerが重要な理由
REST APIを構築する際、コードが進化するにつれてドキュメンテーションが古くなることがよくあります。Swaggerは、ソースコードからドキュメンテーションを生成することで、これを解決します。インタラクティブなSwagger UIは、ブラウザから直接エンドポイントをテストできるため、開発者体験を大幅に向上させます。
マイクロサービスやパブリックAPIを構築するチームにとって、Swaggerドキュメンテーションは次の点で不可欠です:
- クライアント生成:複数の言語でクライアントライブラリを自動生成
- 契約テスト:定義されたスキーマに対してリクエストとレスポンスを検証
- チーム協力:API契約のための単一の真実の出所を提供
- 開発者オンボーディング:新しいチームメンバーがAPIをインタラクティブに探索可能
swaggoの導入
swaggoライブラリは、GoアプリケーションにSwaggerサポートを追加するための最も人気のあるツールです。コード内の特別なコメントを解析し、OpenAPI 3.0仕様ファイルを生成します。
インストール
まず、swag CLIツールをインストールします:
go install github.com/swaggo/swag/cmd/swag@latest
その後、使用するフレームワークに応じたSwaggerミドルウェアパッケージを追加します。Ginの場合:
go get -u github.com/swaggo/gin-swagger
go get -u github.com/swaggo/files
Echoの場合:
go get -u github.com/swaggo/echo-swagger
Fiberの場合:
go get -u github.com/gofiber/swagger
基本的な設定
main.goファイルに一般的なAPI情報を追加して開始します。GoでREST APIを実装と同様に、注釈は明確かつ記述的である必要があります:
// @title Product API
// @version 1.0
// @description Swaggerドキュメンテーション付きの製品管理API
// @termsOfService http://swagger.io/terms/
// @contact.name APIサポート
// @contact.url http://www.swagger.io/support
// @contact.email support@swagger.io
// @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
// @host localhost:8080
// @BasePath /api/v1
// @securityDefinitions.apikey Bearer
// @in header
// @name Authorization
// @description Type "Bearer" followed by a space and JWT token.
func main() {
// アプリケーションコード
}
Ginフレームワークでの実装
Ginを使用して完全な例を実装しましょう。まず、構造タグ付きのデータモデルを定義します:
type Product struct {
ID int `json:"id" example:"1"`
Name string `json:"name" example:"Laptop" binding:"required"`
Description string `json:"description" example:"High-performance laptop"`
Price float64 `json:"price" example:"999.99" binding:"required,gt=0"`
Stock int `json:"stock" example:"50"`
}
type ErrorResponse struct {
Error string `json:"error" example:"Invalid input"`
Message string `json:"message" example:"Product name is required"`
}
今、ハンドラ関数を注釈付けましょう。データベース操作を扱う際、これらの注釈はデータフローをドキュメント化します:
// GetProduct godoc
// @Summary IDで製品を取得
// @Description 独自の識別子で1つの製品を取得
// @Tags products
// @Accept json
// @Produce json
// @Param id path int true "製品ID"
// @Success 200 {object} Product
// @Failure 400 {object} ErrorResponse
// @Failure 404 {object} ErrorResponse
// @Router /products/{id} [get]
func GetProduct(c *gin.Context) {
id := c.Param("id")
// 実装ここ
c.JSON(200, Product{ID: 1, Name: "Laptop", Price: 999.99})
}
// CreateProduct godoc
// @Summary 新しい製品を作成
// @Description カタログに新しい製品を追加
// @Tags products
// @Accept json
// @Produce json
// @Param product body Product true "製品オブジェクト"
// @Success 201 {object} Product
// @Failure 400 {object} ErrorResponse
// @Security Bearer
// @Router /products [post]
func CreateProduct(c *gin.Context) {
var product Product
if err := c.ShouldBindJSON(&product); err != nil {
c.JSON(400, ErrorResponse{Error: "Bad Request", Message: err.Error()})
return
}
// データベースに保存
c.JSON(201, product)
}
ドキュメンテーションの生成
コードを注釈付けた後、Swaggerドキュメンテーションを生成します:
swag init
これにより、docsフォルダにswagger.json、swagger.yaml、Goファイルが作成されます。Swaggerエンドポイントをインポートして登録します:
package main
import (
"github.com/gin-gonic/gin"
swaggerFiles "github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"
_ "yourproject/docs" // 生成されたドキュメンテーションのインポート
)
func main() {
r := gin.Default()
// APIルート
v1 := r.Group("/api/v1")
{
v1.GET("/products/:id", GetProduct)
v1.POST("/products", CreateProduct)
}
// Swaggerエンドポイント
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
r.Run(":8080")
}
今、インタラクティブなAPIドキュメンテーションにアクセスできます:http://localhost:8080/swagger/index.html。
Echoフレームワークでの実装
Echoユーザーは、Echo固有のミドルウェアを使用して類似のパターンに従います:
package main
import (
"github.com/labstack/echo/v4"
echoSwagger "github.com/swaggo/echo-swagger"
_ "yourproject/docs"
)
func main() {
e := echo.New()
// APIルート
api := e.Group("/api/v1")
api.GET("/products/:id", getProduct)
api.POST("/products", createProduct)
// Swaggerエンドポイント
e.GET("/swagger/*", echoSwagger.WrapHandler)
e.Start(":8080")
}
Fiberフレームワークでの実装
Fiberの実装も同様に簡単です:
package main
import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/swagger"
_ "yourproject/docs"
)
func main() {
app := fiber.New()
// APIルート
api := app.Group("/api/v1")
api.Get("/products/:id", getProduct)
api.Post("/products", createProduct)
// Swaggerエンドポイント
app.Get("/swagger/*", swagger.HandlerDefault)
app.Listen(":8080")
}
高度なSwagger注釈
複雑なリクエストボディのドキュメンテーション
ネストされた構造や配列の場合:
type CreateOrderRequest struct {
CustomerID int `json:"customer_id" example:"123" binding:"required"`
Items []OrderItem `json:"items" binding:"required,min=1"`
ShippingAddress Address `json:"shipping_address" binding:"required"`
}
type OrderItem struct {
ProductID int `json:"product_id" example:"1" binding:"required"`
Quantity int `json:"quantity" example:"2" binding:"required,min=1"`
}
type Address struct {
Street string `json:"street" example:"123 Main St" binding:"required"`
City string `json:"city" example:"New York" binding:"required"`
ZipCode string `json:"zip_code" example:"10001" binding:"required"`
}
// CreateOrder godoc
// @Summary 新しい注文を作成
// @Description 複数のアイテムと配送情報を含む注文を作成
// @Tags orders
// @Accept json
// @Produce json
// @Param order body CreateOrderRequest true "注文詳細"
// @Success 201 {object} Order
// @Failure 400 {object} ErrorResponse
// @Failure 422 {object} ErrorResponse
// @Security Bearer
// @Router /orders [post]
func CreateOrder(c *gin.Context) {
// 実装
}
ファイルアップロードのドキュメンテーション
// UploadImage godoc
// @Summary 製品画像をアップロード
// @Description 製品用の画像ファイルをアップロード
// @Tags products
// @Accept multipart/form-data
// @Produce json
// @Param id path int true "製品ID"
// @Param file formData file true "画像ファイル"
// @Success 200 {object} map[string]string
// @Failure 400 {object} ErrorResponse
// @Security Bearer
// @Router /products/{id}/image [post]
func UploadImage(c *gin.Context) {
file, _ := c.FormFile("file")
// アップロード処理
}
クエリパラメータとページネーションのドキュメンテーション
// ListProducts godoc
// @Summary ページネーション付き製品一覧
// @Description オプションのフィルタリング付きページネーション付き製品一覧
// @Tags products
// @Accept json
// @Produce json
// @Param page query int false "ページ番号" default(1)
// @Param page_size query int false "ページあたりのアイテム数" default(10)
// @Param category query string false "カテゴリでフィルタリング"
// @Param min_price query number false "最小価格"
// @Param max_price query number false "最大価格"
// @Success 200 {array} Product
// @Failure 400 {object} ErrorResponse
// @Router /products [get]
func ListProducts(c *gin.Context) {
// ページネーション付き実装
}
認証とセキュリティ
APIの認証方法をドキュメント化してください。マルチテナントアプリケーションにおいて、適切な認証ドキュメントは非常に重要です:
Bearerトークン認証
// @securityDefinitions.apikey Bearer
// @in header
// @name Authorization
// @description "Bearer"に続いてスペースとJWTトークンを入力してください。
APIキー認証
// @securityDefinitions.apikey ApiKeyAuth
// @in header
// @name X-API-Key
// @description 認証用のAPIキー
OAuth2認証
// @securitydefinitions.oauth2.application OAuth2Application
// @tokenUrl https://example.com/oauth/token
// @scope.write 書き込みアクセスを付与
// @scope.admin 読み書きアクセスを管理情報に付与
ベーシック認証
// @securityDefinitions.basic BasicAuth
特定のエンドポイントにセキュリティを適用します:
// @Security Bearer
// @Security ApiKeyAuth
Swagger UIのカスタマイズ
Swagger UIの外観と動作をカスタマイズできます:
// カスタム設定
url := ginSwagger.URL("http://localhost:8080/swagger/doc.json")
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler, url))
// カスタムタイトル付き
r.GET("/swagger/*any", ginSwagger.WrapHandler(
swaggerFiles.Handler,
ginSwagger.URL("http://localhost:8080/swagger/doc.json"),
ginSwagger.DefaultModelsExpandDepth(-1),
))
本番環境でSwaggerを無効にします:
if os.Getenv("ENV") != "production" {
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
}
CI/CDとの統合
CI/CDパイプラインでSwaggerドキュメンテーションの生成を自動化します:
# GitHub Actionsの例
name: Generate Swagger Docs
on: [push]
jobs:
swagger:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.21'
- name: Install swag
run: go install github.com/swaggo/swag/cmd/swag@latest
- name: Generate Swagger docs
run: swag init
- name: Commit docs
run: |
git config user.name github-actions
git config user.email github-actions@github.com
git add docs/
git commit -m "Update Swagger documentation" || exit 0
git push
ベストプラクティス
1. 一貫した注釈スタイル
すべてのエンドポイントで一貫したフォーマットを維持します:
// HandlerName godoc
// @Summary 簡潔な説明(50文字未満)
// @Description エンドポイントが何をするかの詳細な説明
// @Tags リソース名
// @Accept json
// @Produce json
// @Param name location type required "説明"
// @Success 200 {object} ResponseType
// @Failure 400 {object} ErrorResponse
// @Router /path [method]
2. 説明的な例の使用
API消費者に役立つ現実的な例を追加します:
type User struct {
ID int `json:"id" example:"1"`
Email string `json:"email" example:"user@example.com"`
CreatedAt time.Time `json:"created_at" example:"2025-01-15T10:30:00Z"`
}
3. すべての応答コードをドキュメント化
すべての可能なHTTPステータスコードを含めます:
// @Success 200 {object} Product
// @Success 201 {object} Product
// @Failure 400 {object} ErrorResponse "Bad Request"
// @Failure 401 {object} ErrorResponse "Unauthorized"
// @Failure 403 {object} ErrorResponse "Forbidden"
// @Failure 404 {object} ErrorResponse "Not Found"
// @Failure 422 {object} ErrorResponse "Validation Error"
// @Failure 500 {object} ErrorResponse "Internal Server Error"
4. APIのバージョン指定
ベースパスに適切なバージョン指定を使用します:
// @BasePath /api/v1
コードをそれに応じて整理します:
v1 := r.Group("/api/v1")
v2 := r.Group("/api/v2")
5. 関連するエンドポイントのグループ化
論理的にエンドポイントを整理するためにタグを使用します:
// @Tags products
// @Tags orders
// @Tags users
6. ドキュメンテーションを最新に保つ
変更が反映されない場合は、ドキュメンテーションを再生成してください:
swag init --parseDependency --parseInternal
--parseDependencyフラグは外部依存関係を解析し、--parseInternalフラグは内部パッケージを解析します。
7. カスタムタイプが認識されない場合
外部パッケージのタイプに対してswaggertypeタグを使用します:
type CustomTime struct {
time.Time
}
func (CustomTime) SwaggerDoc() map[string]string {
return map[string]string{
"time": "RFC3339タイムスタンプ",
}
}
またはswaggertypeタグを使用します:
type Product struct {
ID int `json:"id"`
UpdatedAt CustomTime `json:"updated_at" swaggertype:"string" format:"date-time"`
}
8. 配列と列挙型
配列タイプと列挙型をドキュメント化します:
type Filter struct {
Status []string `json:"status" enums:"active,inactive,pending"`
Tags []string `json:"tags"`
}
// @Param status query string false "ステータスフィルタ" Enums(active, inactive, pending)
代替アプローチ
swaggoが最も人気のある選択肢ですが、他のオプションも存在します:
go-swagger
より機能豊かですが複雑な代替手段:
brew install go-swagger
swagger generate spec -o ./swagger.json
手動でOpenAPIファイルを記述
完全な制御を求める場合、YAMLでOpenAPI仕様を手動で記述します:
openapi: 3.0.0
info:
title: Product API
version: 1.0.0
paths:
/products:
get:
summary: 製品一覧
responses:
'200':
description: 成功
その後、次のように提供します:
r.StaticFile("/openapi.yaml", "./openapi.yaml")
AIおよびLLMとの統合
AIサービスと統合するAPIを構築する際、適切なドキュメンテーションが非常に重要です。たとえば、構造化されたLLM出力を扱う際、Swaggerは複雑なリクエストおよびレスポンススキーマをドキュメント化します:
type LLMRequest struct {
Prompt string `json:"prompt" example:"このテキストを要約してください"`
Model string `json:"model" example:"qwen2.5:latest"`
Temperature float64 `json:"temperature" example:"0.7" minimum:"0" maximum:"2"`
MaxTokens int `json:"max_tokens" example:"1000" minimum:"1"`
Schema map[string]interface{} `json:"schema,omitempty"`
}
// GenerateStructured godoc
// @Summary 構造化されたLLM出力を生成
// @Description 制約付き出力スキーマでテキストを生成
// @Tags llm
// @Accept json
// @Produce json
// @Param request body LLMRequest true "LLMパラメータ"
// @Success 200 {object} map[string]interface{}
// @Failure 400 {object} ErrorResponse
// @Router /llm/generate [post]
func GenerateStructured(c *gin.Context) {
// 実装
}
パフォーマンスの考慮点
Swaggerドキュメンテーションは、パフォーマンスへの影響が最小限です:
- ビルド時間:
swag initは、ほとんどのプロジェクトで1〜3秒かかります - ランタイム:ドキュメンテーションは起動時に一度だけ読み込まれます
- メモリ:通常、バイナリサイズに1〜2MBを追加します
- 応答時間:APIエンドポイント自体には影響を与えません
非常に大きなAPI(100以上のエンドポイント)の場合、次を考慮してください:
- 複数のSwaggerファイルに分割
- Swagger UIアセットを遅延読み込み
- ドキュメンテーションを別のサービスで提供
セキュリティの考慮点
Swaggerドキュメンテーションを公開する際には:
- 本番環境で無効にする(APIが内部の場合):
if os.Getenv("ENV") == "production" {
// Swaggerエンドポイントを登録しない
return
}
- 認証を追加:
authorized := r.Group("/swagger")
authorized.Use(AuthMiddleware())
authorized.GET("/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
- エンドポイントにレート制限を追加:
r.GET("/swagger/*any", RateLimitMiddleware(), ginSwagger.WrapHandler(swaggerFiles.Handler))
- 内部詳細の公開を絶対にしない:
- 内部エンドポイントをドキュメント化しない
- データベーススキーマを直接公開しない
- ドキュメンテーションのエラーメッセージを sanitize
結論
Go APIにSwaggerドキュメンテーションを追加することで、開発者体験は推測からガイド付きの探索へと変化します。swaggoライブラリは、コード注釈から包括的なOpenAPIドキュメンテーションを生成することで、このプロセスを簡単に行います。
重要なポイント:
- 基本的な注釈から始め、段階的に拡張
- CI/CDを通じてドキュメンテーションをコードと同期
- 開発中にインタラクティブなテストのためにSwagger UIを使用
- 認証、エラー、エッジケースを丁寧にドキュメント化
- ドキュメンテーションを公開する際のセキュリティ上の考慮点を考慮
マイクロサービス、パブリックAPI、または内部ツールを構築する際、Swaggerドキュメンテーションはサポート負担の削減、オンボーディングの加速、およびより良いAPI設計に恩恵をもたらします。注釈構文の学習にかかる初期投資はすぐに日常的になり、自動生成によりドキュメンテーションが実装に後れを取ることはありません。
Go開発者にとって、強い型付け、コード生成、swaggoの注釈システムの組み合わせは、APIドキュメンテーションを開発プロセスの一部として自然に統合する強力なワークフローを作成します。
有用なリンク
- Goチートシート
- GoでREST APIを構築
- PostgreSQL用のGo ORMs比較:GORM vs Ent vs Bun vs sqlc
- マルチテナントデータベースパターンとGoでの例
- 構造化されたLLM出力:Ollama、Qwen3、PythonおよびGoでの例
- AWS Lambdaパフォーマンス:JavaScript vs Python vs Golang