コンテンツにスキップ

よくある質問

開発中にライブリロードを有効にするには?

Section titled “開発中にライブリロードを有効にするには?”

開発中の自動ライブリロードにはAirを使用します。Airはファイルを監視し、変更が検出されるとアプリケーションを自動的にリビルド/リスタートします。

Installation:

Terminal window
go install github.com/air-verse/air@latest

Setup:

Create a .air.toml configuration file in your project root:

Terminal window
air init

Then run air in your project directory instead of go run:

Terminal window
air

Air will watch your .go files and automatically rebuild/restart your Gin application on changes. See the Air documentation for configuration options.

公式のgin-contrib/corsミドルウェアを使用します:

package main
import (
"time"
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
// Default CORS configuration
r.Use(cors.Default())
// Or customize CORS settings
r.Use(cors.New(cors.Config{
AllowOrigins: []string{"https://example.com"},
AllowMethods: []string{"GET", "POST", "PUT", "DELETE"},
AllowHeaders: []string{"Origin", "Content-Type", "Authorization"},
ExposeHeaders: []string{"Content-Length"},
AllowCredentials: true,
MaxAge: 12 * time.Hour,
}))
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "pong"})
})
r.Run()
}

For a complete security overview, see Security best practices.

静的ファイルを配信するには?

Section titled “静的ファイルを配信するには?”

Use Static() or StaticFS() to serve static files:

func main() {
r := gin.Default()
// Serve files from ./assets directory at /assets/*
r.Static("/assets", "./assets")
// Serve a single file
r.StaticFile("/favicon.ico", "./resources/favicon.ico")
// Serve from embedded filesystem (Go 1.16+)
r.StaticFS("/public", http.FS(embedFS))
r.Run()
}

See Serving data from file for more details.

ファイルアップロードを処理するには?

Section titled “ファイルアップロードを処理するには?”

Use FormFile() for single files or MultipartForm() for multiple files:

// Single file upload
r.POST("/upload", func(c *gin.Context) {
file, _ := c.FormFile("file")
c.SaveUploadedFile(file, "./uploads/"+file.Filename)
c.String(200, "File %s uploaded successfully", file.Filename)
})
// Multiple files upload
r.POST("/upload-multiple", func(c *gin.Context) {
form, _ := c.MultipartForm()
files := form.File["files"]
for _, file := range files {
c.SaveUploadedFile(file, "./uploads/"+file.Filename)
}
c.String(200, "%d files uploaded", len(files))
})

See the Upload file documentation for more details.

Use gin-contrib/jwt or implement custom middleware. Here’s a minimal example:

package main
import (
"net/http"
"time"
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt/v5"
)
var jwtSecret = []byte("your-secret-key")
type Claims struct {
Username string `json:"username"`
jwt.RegisteredClaims
}
func AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
tokenString := c.GetHeader("Authorization")
if tokenString == "" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Missing authorization token"})
c.Abort()
return
}
// Remove "Bearer " prefix if present
if len(tokenString) > 7 && tokenString[:7] == "Bearer " {
tokenString = tokenString[7:]
}
token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
return jwtSecret, nil
})
if err != nil || !token.Valid {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"})
c.Abort()
return
}
if claims, ok := token.Claims.(*Claims); ok {
c.Set("username", claims.Username)
c.Next()
}
}
}

For session-based authentication, see Session management.

リクエストロギングを設定するには?

Section titled “リクエストロギングを設定するには?”

Gin includes a default logger middleware via gin.Default(). For structured JSON logging in production, see Structured logging.

For basic log customization:

r := gin.New()
r.Use(gin.LoggerWithConfig(gin.LoggerConfig{
SkipPaths: []string{"/healthz"},
}))
r.Use(gin.Recovery())

See the Logging section for all options including custom formats, file output, and skipping query strings.

グレースフルシャットダウンを処理するには?

Section titled “グレースフルシャットダウンを処理するには?”

See Graceful restart or stop for a complete guide with code examples.

”405 Method Not Allowed”の代わりに”404 Not Found”が返されるのはなぜ?

Section titled “”405 Method Not Allowed”の代わりに”404 Not Found”が返されるのはなぜ?”

By default, Gin returns 404 for routes that don’t support the requested HTTP method. Set HandleMethodNotAllowed = true to return 405 instead:

r := gin.Default()
r.HandleMethodNotAllowed = true
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "pong"})
})
r.Run()
Terminal window
$ curl -X POST localhost:8080/ping
HTTP/1.1 405 Method Not Allowed
Allow: GET

クエリパラメータとPOSTデータを一緒にバインドするには?

Section titled “クエリパラメータとPOSTデータを一緒にバインドするには?”

Use ShouldBind() which automatically selects the binding based on content type:

type User struct {
Name string `form:"name" json:"name"`
Email string `form:"email" json:"email"`
Page int `form:"page"`
}
r.POST("/user", func(c *gin.Context) {
var user User
if err := c.ShouldBind(&user); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
c.JSON(200, user)
})

See the Binding section for all binding options.

リクエストデータをバリデーションするには?

Section titled “リクエストデータをバリデーションするには?”

Gin uses go-playground/validator for validation. Add validation tags to your structs:

type User struct {
Name string `json:"name" binding:"required,min=3,max=50"`
Email string `json:"email" binding:"required,email"`
Age int `json:"age" binding:"gte=0,lte=130"`
}
r.POST("/user", func(c *gin.Context) {
var user User
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
c.JSON(200, gin.H{"message": "User is valid"})
})

See Binding and validation for custom validators and advanced usage.

Ginを本番モードで実行するには?

Section titled “Ginを本番モードで実行するには?”

Set the GIN_MODE environment variable to release:

Terminal window
export GIN_MODE=release
# or
GIN_MODE=release ./your-app

Or set it programmatically:

gin.SetMode(gin.ReleaseMode)

Release mode disables debug logging and improves performance.

Ginでデータベース接続を処理するには?

Section titled “Ginでデータベース接続を処理するには?”

See Database integration for a complete guide covering database/sql, GORM, connection pooling, and dependency injection patterns.

Ginハンドラをテストするには?

Section titled “Ginハンドラをテストするには?”

Use net/http/httptest to test your routes:

func TestPingRoute(t *testing.T) {
router := gin.Default()
router.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "pong"})
})
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/ping", nil)
router.ServeHTTP(w, req)
assert.Equal(t, 200, w.Code)
assert.Contains(t, w.Body.String(), "pong")
}

See the Testing documentation for more examples.

高トラフィック向けにGinを最適化するには?

Section titled “高トラフィック向けにGinを最適化するには?”
  1. Use Release Mode: Set GIN_MODE=release
  2. Disable unnecessary middleware: Only use what you need
  3. Use gin.New() instead of gin.Default() for manual middleware control
  4. Connection pooling: Configure database connection pools (see Database integration)
  5. Caching: Implement caching for frequently accessed data
  6. Load balancing: Use reverse proxy (nginx, HAProxy)
  7. Profiling: Use Go’s pprof to identify bottlenecks
  8. Monitoring: Set up metrics and monitoring to track performance

はい。Ginは多くの企業で本番環境で使用されており、大規模な環境で実戦テスト済みです。本番環境でGinを使用しているプロジェクトの例についてはユーザーをご覧ください。

ルートパラメータが動作しないのはなぜ?

Section titled “ルートパラメータが動作しないのはなぜ?”

Ensure route parameters use : syntax and are properly extracted:

// Correct
r.GET("/user/:id", func(c *gin.Context) {
id := c.Param("id")
c.String(200, "User ID: %s", id)
})
// Not: /user/{id} or /user/<id>

See Parameters in path for details.

ミドルウェアが実行されないのはなぜ?

Section titled “ミドルウェアが実行されないのはなぜ?”

Middleware must be registered before routes or route groups:

// Correct order
r := gin.New()
r.Use(MyMiddleware()) // Register middleware first
r.GET("/ping", handler) // Then routes
// For route groups
auth := r.Group("/admin")
auth.Use(AuthMiddleware()) // Middleware for this group
{
auth.GET("/dashboard", handler)
}

See Using middleware for details.

リクエストバインディングが失敗するのはなぜ?

Section titled “リクエストバインディングが失敗するのはなぜ?”

Common reasons:

  1. Missing binding tags: Add json:"field" or form:"field" tags
  2. Content-Type mismatch: Ensure client sends correct Content-Type header
  3. Validation errors: Check validation tags and requirements
  4. Unexported fields: Only exported (capitalized) struct fields are bound
type User struct {
Name string `json:"name" binding:"required"` // ✓ Correct
Email string `json:"email"` // ✓ Correct
age int `json:"age"` // ✗ Won't bind (unexported)
}

See Binding and validation for details.