ここ最近はあまりAPIGateway+LambdaのRestAPIを作ることはありませんでしたが昨年からGolangに仕事の言語が切り替わったこともあり、改めて作ってみることにしました。
そこで今回はミドルウェアを作ります。
ECSなどでやるのであればGinなどのWebフレームワークのミドルウェアを作れば良いのですが今回はそうはいかないので自分で作って見ます。
なぜミドルウェアを作るのか?
Lamdbaに限らず、Webアプリではほぼ全てのAPIに使う共通的な処理があります。
例えばハンドラーのところの実行前に認証をしたり、入口と出口のロギングなどですね。
他の開発同様に共通処理の部分を作れるように2つのミドルウェアを用意します。
固定の共通処理の場合
速度測定のロギングなどやエラーハンドリング、認証で使うことが多いです。
func middleware(next func(context.Context, events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error)) func(context.Context, events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
return func(ctx context.Context, req events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
// 前処理
// 例: リクエストログの記録
log.Printf("前処理1")
// 次の処理を実行
resp, err := next(ctx, req)
// 後処理
// 例: 応答ログの記録
log.Printf("後処理1")
return resp, err
}
}
前処理と後処理の部分を必要に応じて変更してください。
基本的に値を渡したりなどしたい場合はctxに追加することをお勧めします。
引数を含めたミドルウェア
引数を入れたい場合はクロージャーを変更します。
もう少し細かくやりたい場合はinterfaceを定義して呼び出す関数を定義するなどのやり方があります。
type MyStruct struct {
// ここに必要なフィールドを定義
Value string
}
func createMiddleware(myData *MyStruct) func(func(context.Context, events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error)) func(context.Context, events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
return func(next func(context.Context, events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error)) func(context.Context, events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
return func(ctx context.Context, req events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
// 前処理: ここで構造体を使用
fmt.Printf("ミドルウェアの前処理で使用される構造体の値: %v\n", myData.Value)
// 次の処理を実行
resp, err := next(ctx, req)
// 後処理: ここでも構造体を使用
fmt.Printf("ミドルウェアの後処理で使用される構造体の値: %v\n", myData.Value)
return resp, err
}
}
}
ミドルウェアを呼びだす
先ほど定義した2つのミドルウェアも同じ関数で呼び出すことができます。
func SetMiddlewares(handler func(context.Context, events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error), middlewares ...func(func(context.Context, events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error)) func(context.Context, events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error)) func(context.Context, events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
for i := len(middlewares) - 1; i >= 0; i-- {
handler = middlewares[i](handler)
}
return handler
}
func main() {
combinedHandler := SetMiddlewares(handler, middleware, createMiddleware(&MyStruct{Value: "test"}))
lambda.Start(combinedHandler)
}