1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Gin フレームワーク チートシート

Last updated at Posted at 2025-03-19

Ginパッケージ概要

Ginは、Go言語のための高速で軽量なWebフレームワーク。多くのウェブアプリケーションで必要とされる機能(ルーティング、ミドルウェア、リクエスト/レスポンス処理など)を簡潔に実装できるように設計されている。

基本設定・初期化

// パッケージのインポート
import "github.com/gin-gonic/gin"

// デフォルト設定でエンジンを初期化(ロガーとリカバリーミドルウェア付き)
r := gin.Default()

// ミドルウェアなしの空のエンジンを初期化
// r := gin.New()

// サーバーを起動(デフォルトは8080ポート)
r.Run()

// カスタムポートで起動
r.Run(":3000")

ルーティング

// 基本的なルート定義
r.GET("/path", handlerFunc)
r.POST("/path", handlerFunc)
r.PUT("/path", handlerFunc)
r.DELETE("/path", handlerFunc)
r.PATCH("/path", handlerFunc)
r.HEAD("/path", handlerFunc)
r.OPTIONS("/path", handlerFunc)

// 複数のハンドラーをチェーン
r.GET("/path", middleware1, middleware2, handlerFunc)

// 動的パラメータを持つルート
r.GET("/users/:id", getUserHandler)
r.GET("/users/:id/posts/:post_id", getPostHandler)

// ワイルドカードルート
r.GET("/assets/*filepath", serveAssets)

リクエスト処理

// ハンドラー関数の基本形
func handlerFunc(c *gin.Context) {
    // 処理を実装
}

// URLパラメータの取得
func getUserHandler(c *gin.Context) {
    id := c.Param("id") // /users/:id からidを取得
}

// クエリパラメータの取得
func listHandler(c *gin.Context) {
    limit := c.DefaultQuery("limit", "10") // ?limit=x または デフォルト値
    page := c.Query("page") // ?page=x または 空文字列
}

// フォームデータの取得
func formHandler(c *gin.Context) {
    name := c.PostForm("name")
    email := c.DefaultPostForm("email", "no-email")
}

// リクエストボディをバインド(JSON)
func createHandler(c *gin.Context) {
    var json struct {
        Name string `json:"name" binding:"required"`
        Age  int    `json:"age"`
    }

    if err := c.ShouldBindJSON(&json); err != nil {
        c.JSON(400, gin.H{"error": err.Error()})
        return
    }
}

// マルチパートフォームのファイルアップロード
func uploadHandler(c *gin.Context) {
    file, _ := c.FormFile("file")
    c.SaveUploadedFile(file, dst)
}

レスポンス処理

// JSONレスポンス
c.JSON(200, gin.H{
    "message": "success",
    "data": item,
})

// 構造体を直接JSONとして返す
c.JSON(200, user)

// HTML返答
c.HTML(200, "template.html", gin.H{
    "title": "Hello",
})

// リダイレクト
c.Redirect(302, "/new-url")

// プレーンテキスト
c.String(200, "Hello %s", name)

// ステータスコードのみ
c.Status(204) // No Content

// ファイル送信
c.File("path/to/file")

// ストリーム送信
c.DataFromReader(200, contentLength, contentType, reader, extraHeaders)

ミドルウェア

// グローバルミドルウェア
r.Use(gin.Logger())
r.Use(gin.Recovery())

// カスタムミドルウェア
func AuthMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        // 認証処理
        if !authenticated {
            c.AbortWithStatusJSON(401, gin.H{"error": "unauthorized"})
            return
        }
        // 次のハンドラーへ進む
        c.Next()
    }
}

// ミドルウェアの適用
r.Use(AuthMiddleware())

// 特定のルートにのみミドルウェアを適用
r.GET("/admin", AuthMiddleware(), adminHandler)

// ミドルウェア内でリクエスト処理をスキップ
c.Abort()

// CORS設定ミドルウェア
r.Use(func(c *gin.Context) {
    c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
    c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
    c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")

    if c.Request.Method == "OPTIONS" {
        c.AbortWithStatus(204)
        return
    }

    c.Next()
})

エラーハンドリング

// エラーレスポンス
c.JSON(http.StatusBadRequest, gin.H{"error": "Bad request"})
c.JSON(http.StatusNotFound, gin.H{"error": "Resource not found"})
c.JSON(http.StatusInternalServerError, gin.H{"error": "Internal server error"})

// エラーチェックパターン
if err != nil {
    c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
    return
}

// パニックからの回復(gin.Defaultには含まれる)
r.Use(gin.Recovery())

バインディング・バリデーション

// バインディングタグがついたモデル定義
type User struct {
    Name     string `json:"name" binding:"required"`
    Age      int    `json:"age" binding:"gte=0,lte=130"`
    Email    string `json:"email" binding:"required,email"`
    Password string `json:"password" binding:"required,min=8"`
}

// 様々なバインディング方法
c.ShouldBindJSON(&obj)        // JSON
c.ShouldBindXML(&obj)         // XML
c.ShouldBindQuery(&obj)       // クエリパラメータ
c.ShouldBindYAML(&obj)        // YAML
c.ShouldBindUri(&obj)         // URIパラメータ
c.ShouldBindHeader(&obj)      // ヘッダー
c.ShouldBindWith(&obj, binding.Form) // カスタムバインダー

// バインディングエラーのハンドリング
if err := c.ShouldBindJSON(&user); err != nil {
    c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
    return
}

グループ化

// ルートグループの作成
v1 := r.Group("/api/v1")
{
    v1.GET("/users", listUsers)
    v1.POST("/users", createUser)

    // ネストしたグループ
    users := v1.Group("/users")
    {
        users.GET("/:id", getUser)
        users.PUT("/:id", updateUser)
        users.DELETE("/:id", deleteUser)
    }
}

// グループにミドルウェアを適用
authorized := r.Group("/admin", AuthMiddleware())
{
    authorized.GET("/dashboard", dashboardHandler)
}

Swaggerとの統合

// swagコマンドのインストール
// go install github.com/swaggo/swag/cmd/swag@latest

// main.goにSwagger注釈
// @title Task API
// @version 1.0
// @description A simple task management API
// @host localhost:8080
// @BasePath /api/v1

// ハンドラー関数にSwagger注釈
// @Summary      タスク一覧の取得
// @Description  すべてのタスクのリストを返します
// @Tags         tasks
// @Accept       json
// @Produce      json
// @Success      200  {array}   models.Task
// @Router       /tasks [get]

// Swaggerハンドラーのセットアップ
import (
    swaggerFiles "github.com/swaggo/files"
    ginSwagger "github.com/swaggo/gin-swagger"
    _ "yourapp/docs" // 自動生成されたドキュメント
)

func main() {
    r := gin.Default()
    // ...

    r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
}

よくあるユースケース

// 並行処理を安全に行う(タスクリストの例)
var (
    tasks = make(map[string]models.Task)
    mutex = &sync.Mutex{} // 並行アクセスからデータを保護
)

func GetTasks(c *gin.Context) {
    mutex.Lock()
    defer mutex.Unlock()

    // tasksマップへの安全なアクセス
}

// タイムアウト設定
srv := &http.Server{
    Addr:         ":8080",
    Handler:      r,
    ReadTimeout:  5 * time.Second,
    WriteTimeout: 10 * time.Second,
}
srv.ListenAndServe()

// 静的ファイルの提供
r.Static("/assets", "./public/assets")
r.StaticFile("/favicon.ico", "./resources/favicon.ico")

// テンプレートのロード
r.LoadHTMLGlob("templates/*")
r.GET("/", func(c *gin.Context) {
    c.HTML(http.StatusOK, "index.html", gin.H{
        "title": "Main website",
    })
})

デバッグとロギング

// デバッグモード切替
gin.SetMode(gin.DebugMode)   // デフォルト
gin.SetMode(gin.ReleaseMode) // 本番環境用
gin.SetMode(gin.TestMode)    // テスト用

// カスタムロガー設定
r.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {
    return fmt.Sprintf("[%s] \"%s %s %s %d %s \"%s\" %s\"\n",
        param.TimeStamp.Format(time.RFC1123),
        param.Method,
        param.Path,
        param.Request.Proto,
        param.StatusCode,
        param.Latency,
        param.Request.UserAgent(),
        param.ErrorMessage,
    )
}))

// リクエスト情報をログに出力
c.Request.URL.Path   // リクエストパス
c.Request.Method     // HTTPメソッド
c.ClientIP()         // クライアントIP

テスト

// ハンドラーのテスト
func TestPingRoute(t *testing.T) {
    router := setupRouter()

    w := httptest.NewRecorder()
    req, _ := http.NewRequest("GET", "/ping", nil)
    router.ServeHTTP(w, req)

    assert.Equal(t, 200, w.Code)
    assert.Equal(t, "pong", w.Body.String())
}

// JSONレスポンスのテスト
var json map[string]interface{}
err := json.Unmarshal(w.Body.Bytes(), &json)
assert.Nil(t, err)
assert.Equal(t, "success", json["status"])

1
2
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
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?