GoのHTTPミドルウェアやその周辺パッケージを配布する新しいGitHub Orgをはじめました

このエントリは GMOペパボエンジニア Advent Calendar 2023 および、 Go Advent Calendar 2023 シリーズ3 の19 日目の記事です。

以下のエントリでも少し触れられていますが、現在プロキシサーバをGoで書くプロジェクトがあります。

ten-snapon.com

k1low.hatenablog.com

主な実装をしているのは @pyama86 さんで、それはもうブルドーザーのように実装が進んでいるわけですが*1、私も少しだけですが書いています。

必要そうな機能をGoの薄いHTTPミドルウェアハンドラとしてOSSとしていくつか切り出していました。

そして、本体の実装が進むにつれて足りない機能を Pull Request ベースでもらったりしていたのですが、関連OSSを作る必要が発生したりなど個人リポジトリだとまとまらないため、それらをまとめるためだけにGitHub Org を新設しました。

github.com

既に私のリポジトリからのトランスファーは済んでおり、今後はこのOrg上で開発していく予定です。

どうぞよろしくお願いします。

ごく簡単にですが、置いてあるリポジトリについて紹介したいと思います。

rl

github.com

レートリミットを実現するHTTPミドルウェアハンドラです。

Goにおけるレートリミット実装としては go-chi/httprate が有名だと思います。rlもgo-chi/httprateを参考に実装しています。

rlの特徴は interface を満たす実装をつくって注入するだけで

  • http.Requestの情報をもとに異なるレートリミットのルールを動的に適用できる
  • 複数のレートリミットのルールを動的に重ねがけできる

というものです。

「あるホストへのアクセスだけレートリミットを緩和したい」だとか「あるIPからのアクセスだけレートリミットをかけたい」というユースケースに対応するためのものです。

rp

github.com

リバースプロキシサーバです。HTTPミドルウェアハンドラではないです。

rpの特徴は interface を満たす実装をつくって注入するだけで

  • http.Requestの情報をもとに異なるUpstreamを動的に指定できる
  • tls.ClientHelloInfoの情報をもとに証明書を動的に指定できる

というものです。

マルチテナントなサービスの前段などで必要になる機能を想定しています。

rc

github.com

HTTPキャッシュミドルウェアハンドラです。

rpの特徴は interface を満たす実装をつくって注入するだけで

  • RFC 9111にしたがってキャッシュを使用してくれる

というものです。また、

  • キャッシュルールの拡張や切り替えも可能
  • http.Requestの情報をもとに異なるキャッシュルールを適用する

ということも可能です。

rcutil

github.com

rcのためのユーティリティパッケージです。

rc.Cacher の interface を満たしたディスクキャッシュ機能の提供などをしています。

mm

github.com

HTTPミドルウェアハンドラを管理するHTTPミドルウェアハンドラです。

mmの特徴は interface を満たす実装をつくって注入するだけで

  • http.Requestの情報をもとに異なるHTTPミドルウェアハンドラを動的に指定できる

というものです。

動的に切り替える仕組みがないHTTPミドルウェアハンドラに動的切り替え機能を付与したいときに使うイメージです。

ちなみに、すごく短いコードなので全部貼り付けておきます。

package mm

import (
    "net/http"
)

// Builder is a middleware builder.
type Builder interface { //nostyle:ifacenames
    Middleware(req *http.Request) (func(next http.Handler) http.Handler, bool)
}

type mMw struct {
    builders []Builder
}

func newMMw(builders []Builder) *mMw {
    return &mMw{builders: builders}
}

func (mm *mMw) Handler(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        for _, b := range mm.builders {
            mw, ok := b.Middleware(r)
            if !ok {
                continue
            }
            next = mw(next)
        }
        next.ServeHTTP(w, r)
    })
}

// New returns a new middleware-middleware.
func New(builders ...Builder) func(next http.Handler) http.Handler {
    mm := newMMw(builders)
    return mm.Handler
}

以上、と思ったら、先ほど rlutils というパッケージが誕生していました。

github.com

2manymws*2、どうぞよろしくお願いします。

*1:わかる人にはわかると思います。是非間近で見てほしいので、こちらから応募してください。https://recruit.pepabo.com/

*2:名前の由来は2文字リポジトリが多かったことと、Too manyなミドルウェアを置く場所ということと、例のあれです