1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Go言語で複数のMiddlewareを綺麗に取り扱う

Posted at

APIサーバーを開発する際、複数のMiddlewareを実装しなければならない場合があると思います。普通に実装すると、以下のようになると思います。

router.go
func NewRouter() *http.ServeMux {
    mux := http.NewServeMux()
    h := handler.NewHandler()

    mux.Handle("/", middleware.Middleware1(
                        middleware.Middleware2(
                            middleware.Middleware3(
                                h))))
    ...

    return mux
}

このように、通常の書き方ではMiddlewareの数が増えれば増える程ネストが深くなっていき、可読性が損なわれていきます。今回は、Middlewareの数が増えても可読性をある程度確保できないかと思い、調査をしてみました。

解決策

解決策を一言で表すと、「Middlewareをチェインする関数を別途用意する」になります。

utils.go
// Middleware型を定義
type Middleware func(http.Handler) http.Handler

// Middleware型のスライスでハンドラーをWrap
func ChainMiddleware(h http.Handler, ms ...Middleware) http.Handler {
	if len(ms) < 1 {
		return h
	}
	wrapped := h
	for i := len(ms) - 1; i >= 0; i-- {
		wrapped = ms[i](wrapped)
	}
	return wrapped
}

この用意した関数を利用すると、下記のようにルーティングを実装できます。
router.go
func NewRouter() *http.ServeMux {
    mux := http.NewServeMux()
    h := handler.NewHandler()

    mux.Handle("/", middleware.ChainMiddleware(
        h,
        middleware.Middleware1,
        middleware.Middleware2,
        middleware.Middleware3,
    )
    ...

    return mux
}

コードの量自体にはほとんど変化がありませんが、可読性は上がっていると思います。さらに、複数のパターンで全く同じMiddlewareが呼び出される場合には、Middlewareのスライスを変数に格納することで、コードの量を大幅に減らすことができます。
router.go
func NewRouter() *http.ServeMux {
    mux := http.NewServeMux()
    h := handler.NewHandler()
    ms := []middleware.Middleware{
        middleware.Middleware1,
        middleware.Middleware2,
        middleware.Middleware3
    }
    mux.Handle("/", middleware.ChainMiddleware(h, ms)
    mux.Handle("/p1", middleware.ChainMiddleware(h, ms)
    mux.Handle("/p2", middleware.ChainMiddleware(h, ms)
    ...

    return mux
}

注意点

ただし、呼び出されるMiddlewareの順番は、スライスに格納される順番に依存するので、ネストが浅い順にスライスに格納する必要があります。上記の例を参考にしてみて下さい。

参考にした記事

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?