株式会社エスロジカル
株式会社エスロジカル
SSL証明書(DV、OV、EV)、セキュリティ、Web開発、Linux開発、Go言語

HOME > 技術ドキュメント > Go Gin REST API 開発入門

Go 言語 Gin フレームワーク REST API 開発入門


Gin は Go 言語で最も広く使われている Web フレームワークの一つで、 標準ライブラリより高速なルーティングと、開発効率を高める豊富なユーティリティを提供します。
本ドキュメントでは Gin を使った REST API の基本構成から、バリデーション・ミドルウェア・DB 連携・テストまでを解説します。


mkdir myapi && cd myapi
go mod init github.com/yourname/myapi

# Gin と必要パッケージを追加
go get github.com/gin-gonic/gin
go get github.com/gin-contrib/cors

Gin のルーティングは HTTP メソッドとパスを直接記述します。

// main.go
package main

import (
    "net/http"
    "github.com/gin-gonic/gin"
)

type User struct {
    ID   uint   `json:"id"`
    Name string `json:"name"`
    Email string `json:"email"`
}

var users = []User{
    {ID: 1, Name: "Alice", Email: "alice@example.com"},
    {ID: 2, Name: "Bob",   Email: "bob@example.com"},
}

func main() {
    r := gin.Default()  // Logger と Recovery ミドルウェアを含む

    // ルートグループ
    api := r.Group("/api/v1")
    {
        api.GET("/users",      listUsers)
        api.GET("/users/:id",  getUser)
        api.POST("/users",     createUser)
        api.PUT("/users/:id",  updateUser)
        api.DELETE("/users/:id", deleteUser)
    }

    r.Run(":8080")
}

func listUsers(c *gin.Context) {
    c.JSON(http.StatusOK, gin.H{"users": users})
}

func getUser(c *gin.Context) {
    id := c.Param("id")
    c.JSON(http.StatusOK, gin.H{"id": id})
}

ShouldBindJSON でリクエストボディを構造体にバインドします。 binding:"required" タグでバリデーションが自動的に行われます。

type CreateUserRequest struct {
    Name  string `json:"name"  binding:"required,min=1,max=50"`
    Email string `json:"email" binding:"required,email"`
    Age   int    `json:"age"   binding:"omitempty,gte=0,lte=150"`
}

func createUser(c *gin.Context) {
    var req CreateUserRequest
    if err := c.ShouldBindJSON(&req); err != nil {
        // バリデーションエラーを整形して返す
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    newUser := User{
        ID:    uint(len(users) + 1),
        Name:  req.Name,
        Email: req.Email,
    }
    users = append(users, newUser)
    c.JSON(http.StatusCreated, gin.H{"user": newUser})
}

クエリパラメータは c.Query / c.DefaultQuery で取得できます。

// GET /api/v1/users?page=1&limit=20
func listUsers(c *gin.Context) {
    page  := c.DefaultQuery("page",  "1")
    limit := c.DefaultQuery("limit", "20")
    c.JSON(http.StatusOK, gin.H{"page": page, "limit": limit, "users": users})
}

Gin のミドルウェアは r.Use() または グループ単位で適用できます。

import "github.com/gin-contrib/cors"

func main() {
    r := gin.New()

    // ロギングミドルウェア(カスタム)
    r.Use(gin.LoggerWithFormatter(func(p gin.LogFormatterParams) string {
        return fmt.Sprintf("[%s] %s %s %d %s\n",
            p.TimeStamp.Format(time.RFC3339),
            p.Method, p.Path, p.StatusCode, p.Latency)
    }))
    r.Use(gin.Recovery())

    // CORS ミドルウェア
    r.Use(cors.New(cors.Config{
        AllowOrigins:     []string{"https://example.com"},
        AllowMethods:     []string{"GET", "POST", "PUT", "DELETE"},
        AllowHeaders:     []string{"Content-Type", "Authorization"},
        AllowCredentials: true,
    }))

    // 認証が必要なグループ
    auth := r.Group("/api/v1")
    auth.Use(authMiddleware())
    {
        auth.GET("/profile", getProfile)
    }

    r.Run(":8080")
}

// Bearer トークン認証ミドルウェアの例
func authMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        token := c.GetHeader("Authorization")
        if token != "Bearer valid-token" {
            c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
            return
        }
        c.Set("userID", 1)
        c.Next()
    }
}

go get gorm.io/gorm
go get gorm.io/driver/postgres
import (
    "gorm.io/gorm"
    "gorm.io/driver/postgres"
)

type User struct {
    gorm.Model
    Name  string `gorm:"size:50;not null" json:"name"`
    Email string `gorm:"uniqueIndex;not null" json:"email"`
}

func initDB() *gorm.DB {
    dsn := "host=localhost user=myuser password=mypass dbname=mydb port=5432 sslmode=disable"
    db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
    if err != nil {
        log.Fatal("DB 接続失敗:", err)
    }
    db.AutoMigrate(&User{})
    return db
}

// ハンドラーで DB を使う例
func createUserDB(db *gorm.DB) gin.HandlerFunc {
    return func(c *gin.Context) {
        var req CreateUserRequest
        if err := c.ShouldBindJSON(&req); err != nil {
            c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
            return
        }
        user := User{Name: req.Name, Email: req.Email}
        if result := db.Create(&user); result.Error != nil {
            c.JSON(http.StatusInternalServerError, gin.H{"error": "DB error"})
            return
        }
        c.JSON(http.StatusCreated, user)
    }
}

// main_test.go
package main

import (
    "bytes"
    "encoding/json"
    "net/http"
    "net/http/httptest"
    "testing"
    "github.com/gin-gonic/gin"
)

func setupRouter() *gin.Engine {
    gin.SetMode(gin.TestMode)
    r := gin.Default()
    r.GET("/api/v1/users", listUsers)
    r.POST("/api/v1/users", createUser)
    return r
}

func TestListUsers(t *testing.T) {
    r := setupRouter()
    w := httptest.NewRecorder()
    req, _ := http.NewRequest("GET", "/api/v1/users", nil)
    r.ServeHTTP(w, req)

    if w.Code != http.StatusOK {
        t.Errorf("期待: 200, 実際: %d", w.Code)
    }
}

func TestCreateUser(t *testing.T) {
    r := setupRouter()
    body := `{"name":"Charlie","email":"charlie@example.com"}`
    w := httptest.NewRecorder()
    req, _ := http.NewRequest("POST", "/api/v1/users", bytes.NewBufferString(body))
    req.Header.Set("Content-Type", "application/json")
    r.ServeHTTP(w, req)

    if w.Code != http.StatusCreated {
        t.Errorf("期待: 201, 実際: %d, body: %s", w.Code, w.Body.String())
    }
}
go test ./... -v

本番環境では Nginx をリバースプロキシとして前段に置き、 SSL証明書で HTTPS 化することが標準的な構成です。
エスロジカルではデジサート・サイバートラストの正規取扱代理店として、 2009年から16年以上、RapidSSL 3,960円/1年(税込)〜でSSL証明書を販売しています。審査サポート・インストール代行も対応しています。

SSL証明書の購入はこちら / Nginx SSL/TLS 設定 / Go 言語 Web アプリ入門(net/http)


← 技術ドキュメント一覧へ戻る