2026年6月27日土曜日

Go + gin でレスポンスモデルを管理する

Go + gin でレスポンスモデルを管理する

概要

前回の続きです
レスポンスをハンドラ内でそのまま返していましたが別モジュールとして管理します
またハンドラも別モジュール化します

環境

  • macOS 26.5.1
  • golang 1.26.4
    • gin 1.12.0

レスポンスモデル

成功時のモデルと失敗時のモデルを管理します
またそのモデルを使ってレスポンス情報を生成するメソッドも作成します
本当はこのメソッドも別モジュールのほうがいいかなと思います

  • vim model/response.go
package model

import (
        "net/http"

        "github.com/gin-gonic/gin"
)

type APIResponse struct {
        Success bool        `json:"success"`
        Data    interface{} `json:"data,omitempty"`
        Error   *APIError   `json:"error,omitempty"`
}

type APIError struct {
        Code    string `json:"code"`
        Message string `json:"message"`
}

func RespondSuccess(c *gin.Context, data interface{}) {
        c.JSON(http.StatusOK, APIResponse{
                Success: true,
                Data:    data,
        })
}

func RespondError(c *gin.Context, status int, code, message string) {
        c.JSON(status, APIResponse{
                Success: false,
                Error: &APIError{
                        Code:    code,
                        Message: message,
                },
        })
}

ハンドラ

アクションごとに dispatcher に登録するハンドラ関数を別のモジュールに移動します
ここで先程のレスポンスモデルを使います

  • vim handler/action.go
package handler

import (
        "fmt"
        "net/http"
        "strconv"
)

func HelloAction(params map[string]string, method string, r *http.Request) (any, error) {
        name := params["name"]
        if name == "" {
                name = "guest"
        }
        return map[string]string{
                "message": "hello " + name,
        }, nil
}

func SumAction(params map[string]string, method string, r *http.Request) (any, error) {
        aStr := params["a"]
        bStr := params["b"]

        a, err := strconv.Atoi(aStr)
        if err != nil {
                return nil, fmt.Errorf("invalid parameter 'a'")
        }

        b, err := strconv.Atoi(bStr)
        if err != nil {
                return nil, fmt.Errorf("invalid parameter 'b'")
        }

        sum := a + b

        return map[string]interface{}{
                "a":   a,
                "b":   b,
                "sum": sum,
        }, nil
}

main.go の修正

ハンドラ関数がなくなったのでかなりすっきりします

  • vim main.go
package main

import (
        "gin-sample/handler"

        "github.com/gin-gonic/gin"
)

func main() {
        dispatcher := handler.NewDispatcher()

        // ★ handlerから登録
        dispatcher.Register("Hello", handler.HelloAction)
        dispatcher.Register("Sum", handler.SumAction)

        r := gin.Default()

        r.GET("/", handler.HandleAction(dispatcher))
        r.POST("/", handler.HandleAction(dispatcher))

        r.Run()
}

動作確認

  • gofmt -w .
  • go run main.go
curl -X POST http://localhost:8080 \                
  -d "Action=Sum&a=10&b=20"
{"action":"Sum","requestId":"dummy-request-id","result":{"a":10,"b":20,"sum":30}}

curl "http://localhost:8080/?Action=Hello&name=Taro"
{"action":"Hello","requestId":"dummy-request-id","result":{"message":"hello Taro"}}

最後に

エラーハンドリングの共通化ができていないのでそのあたりはやったほうがいいです

0 件のコメント:

コメントを投稿