13
14

More than 3 years have passed since last update.

golangのechoでMiddlewareFuncを使ってみる

Last updated at Posted at 2017-04-04

 自分はWebFrameworkを使う時、データベースのインスタンス等はカスタムMiddlewareを使って開いたり閉じたりしてます。
 最近echoを使ってみて、echoのカスタムMiddlewareのドキュメントってHandlerFuncを使って書いてあるですが、HandlerFuncだと引数が取れなくて困ってしまいました。
 そんでソースを見てたらMiddlewareFuncを発見したって話しです。

前提条件

カスタムコンテキストを定義

 データベースのインスタンスはコンテキストに置くのでカスタムコンテキストを定義(参照:https://echo.labstack.com/guide/context)


package main

import (
    "database/sql"

    "github.com/labstack/echo"
)

// カスタムコンテキスト
type CustomContext struct {
    echo.Context
    DB            *sql.DB
}

MiddlewareFuncの実装

 早速、MiddlewareFuncを実装してみる。とりあえず、カスタムコンテキスト用とDB用とは分けて書いてみる。


package main

import (
    "database/sql"

    "github.com/labstack/echo"
    _ "github.com/go-sql-driver/mysql" // 本当はmain.goに置いほうが良いらしい
)

// カスタムコンテキストを定義するMiddleware
func myCustomContextMiddleware() echo.MiddlewareFunc {
    return func(next echo.HandlerFunc) echo.HandlerFunc {
        return func(c echo.Context) error {
            // カスタムコンテキストを初期化して次へ
            cctx := &CustomContext{
                Context: c,
            }
            return next(cctx)
        }
    }
}

// DBを設定するMiddleware
func myDBMiddleware(datasource string) echo.MiddlewareFunc {
    return func(next echo.HandlerFunc) echo.HandlerFunc {
        return func(c echo.Context) error {
            cctx, ok := c.(*CustomContext)
            if !ok {
                return echo.NewHTTPError(http.StatusInternalServerError, "カスタムコンテキストが取得できません")
            }

            db, err := sql.Open("mysql", datasource)
            if err != nil {
                return echo.NewHTTPError(http.StatusInternalServerError, "DBが取得できません")              
            }
            defer db.Close()

            // DBをコンテキストに設定して次へ
            cctx.DB = db
            return next(cctx)
        }
    }
}

main

後はMiddlewareを適用するだけ。


package main

import (
    "context"
    "database/sql"
    "os"
    "os/signal"
    "syscall"

    "github.com/labstack/echo"
)

func main() {
    e := echo.New()

    // カスタムコンテキスト用Middlewareを適用
    e.Use(myCustomContextMiddleware())

    // DB用Middlewareを適用
    e.Use(myDBMiddleware("データソースは省略"))

    errC := make(chan error)

    go func() {
        if err := e.Start(":8080"); err != nil {
            errC <- err
        }
    }()

    quitC := make(chan os.Signal)
    signal.Notify(quitC, syscall.SiGINT, syscall.SIGTERM)

    select {
    case err := <-errC:
        panic(err)
    case <-quitC:
        shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
        defer cancel()
        if err := e.Shutdown(shutdownCtx); err != nil {
            errC <- err
        }
    }
}

以上

 今回カスタムコンテキスト用とDB用と分けたので必ず先にカスタムコンテキスト用を適用する必要があります。
 DB用はDBを使うグループ(echo.Group)のみに適用したりすると良いかもしれません。

13
14
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
13
14