焼売飯店

GoとかTS、JSとか

hono-middleware-goのご紹介

この記事はHono Advent Calendar 2025の2日目の記事です。

はじめに

皆さんはHonoのMiddlewareを書いたことがありますか?

HonoのドキュメントのCustom Middlewareから引用しますが、HonoのMiddlewareは非常にシンプルな仕組みで、以下のように app.use() に渡したコールバック関数内の、 await next() 呼び出しの前後でContextに対して処理を行うことができます。

// Custom logger
app.use(async (c, next) => {
  console.log(`[${c.req.method}] ${c.req.url}`)
  // ↑次のMiddleware / Handlerの処理の前に実行
  await next()
})

// Add a custom header
app.use('/message/*', async (c, next) => {
  await next()
  // ↓前のMiddleware / Handlerの処理の後に実行
  c.header('x-message', 'This is middleware!')
})

以下はHonoのドキュメントのModify the Response After Nextの例ですが、このように、Handlerが返したResponseをMiddlewareで上書きすることもできてしまいます。

const stripRes = createMiddleware(async (c, next) => {
  await next()
  c.res = undefined
  // Responseを上書き
  c.res = new Response('New Response')
})

このように、HonoのMiddlewareは、リクエスト / レスポンスの処理に介入して好きに加工を行える、大きな柔軟性を持っています。パッと見ただけでも、これなら何でもできそう!という印象になると思います。

ですが、ちょっと待ってください。

何でもできそうといっても、これはTypeScript / JavaScriptで書ける範囲なら何でもできそうという話のようにも見えます。

人によっては、Goの豊富なライブラリを使ってHonoのMiddlewareを書きたいことがあるかもしれないですよね!

そんなあなたのために、hono-middleware-goを紹介します!

github.com

hono-middleware-go

hono-middleware-goは、GoでHonoのMiddlewareを書くためのライブラリです。

厳密には、syumai/workersexp/hono packageを使い、Goで実装されたHono向けMiddlewareを、実際にHonoで動かすためのライブラリとなります。

pkg.go.dev

実は、作ったのは最近のことではなく、1年以上が経過していたようです。今回、この記事を書くにあたって、最新版のGoで動作することを確認しました。

なお、最新のTinyGoでは動作確認がうまくいっていないので、現状はGo専用となります点にご注意ください。

GoによるMiddlewareの実装方法

Middlewareの実装方法はいたってシンプルで、HonoのMiddlewareの形式に則った以下のような関数を実装して、hono.ServeMiddleware関数でServeするだけです。

package

import (
    "fmt"

    "github.com/syumai/workers/exp/hono"
)

func Middleware(c *hono.Context, next func()) {
    fmt.Println("middleware started")
    next()
    fmt.Println("middleware finished")
    // ここでContextもいじれる
    // 例: c.SetStatus(400)
}

func main() {
    hono.ServeMiddleware(Middleware)
}

あとは、上記のコードをWasmにコンパイルした結果をHonoアプリケーション側で読み込んで、 hono-middleware-go から go 関数をインポートしてMiddlewareとして設定します。以下はCloudflare Workersで使った例です。

import { Hono } from "hono";
import { go } from "@syumai/hono-middleware-go";
import mod from "../wasm/middleware.wasm";

const app = new Hono();

// ここでGoで書いたMiddlewareを設定
app.use(go(mod));

// 各Handlerの設定は普段通り
app.get("/", (c) => {
  return c.text("Hello Hono!");
});

export default app;

実際に、この仕組みを使って実装したBasic認証のサーバーを以下のURLから試せます (ユーザー名: user、パスワード: password)。ぜひ試してみてください!

https://hono-middleware-go-basic-auth.syumai.workers.dev/

GitHub: https://github.com/syumai/hono-middleware-go/tree/main/examples/basic-auth-middleware-go

応用例

もちろんですが、 exp/hono では、Contextからリクエスト・レスポンスを読み取ることができます。

これを活用して、プロキシした画像をグレースケール加工するHono MiddlewareをGoで実装した例が以下です。

https://github.com/syumai/hono-middleware-go/blob/main/examples/gray-scale-middleware-go/go/main.go

詳細な解説は割愛しますが、 c.ResponseBody() で、Handlerから返るレスポンスを io.ReadCloser として取得できるので、その中身を image packageでデコードし、加工して改めて返しています。

こちらのサンプルは下記URLから試せます。

おわりに

今回は、Goを使ったHono Middlewareの実装について簡単に紹介しました。 HonoのMiddlewareはインタフェースがシンプルなので、このように他言語を混ぜ込みつつ実装するのも、ちょっとだけ頑張ったら全然可能です。

ぜひ、みなさんも好きな言語でHonoのMiddlewareを書けるようにしてみてください!Goならすぐに試せます!!