GoでのMiddlewareの役割と実装方法についてまとめ

## はじめに

Middlewareは、HTTPリクエストとレスポンスの処理をフック（hook）し、共通の処理を適用するための仕組みのことです。  
Goでは、主に`net/http`パッケージを使用して簡単にMiddlewareを実装することができます。

今回はMiddlewareの基本概念、Goにおける実装方法と活用例を簡単にまとめました。


**対象読者**
- GoのMiddlewareの基本を学びたい方
- 共通の処理を効率的に適用する方法を知りたい方
- 実践的なMiddlewareの書き方を学びたい方

**目次**
1. Middlewarrとは？
   - Middlewareの役割
   - Middlewareを使うメリット
2. GoでのMiddlewareの基本
   - Goの`net/http`を使ったMiddleware
   - シンプルなMiddlewareの実装
3. 実践的なMiddlewareの例
   - ロギングMiddleware
   - 認証Middleware
   - CORS Middleware
4. まとめ

---

## 1. Middlewareとは？

#### **1.1 Middlewareの役割**

Middlewareは、HTTPリクエストを処理する前後で特定の処理を実行する仕組みです。
例えば、以下のような処理をMiddlewareで実装できます。

| 役割 | 説明 |
|------|------|
| **ロギング** | リクエストの情報を記録する |
| **認証** | ユーザーの認証を行う |
| **CORS対応** | クロスオリジンリクエストを許可する |
| **リクエストバリデーション** | リクエストデータの検証を行う |

#### **1.2 Middlewareを使うメリット**

Middlewareを導入することで、以下のような開発効率の向上が期待できます。

- 共通処理を一箇所にまとめられる → コードの重複を削減
- リクエストの前処理・後処理が簡単にできる
- 複数のMiddlewareを組み合わせて柔軟な制御が可能

---

## 2. GoでのMiddlewareの基本

#### **2.1 Goの`net/http`を使ったMiddleware**

Goでは、`http.Handler`をラップする関数を使ってMiddlewareを実装できます。

**Middlewareの基本構造**
```go
package main

import (
    "fmt"
    "net/http"
)

// Middlewareの定義
func middleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        fmt.Println("Middleware: リクエストを処理中...")
        next.ServeHTTP(w, r)
        fmt.Println("Middleware: レスポンスを返しました。")
    })
}

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintln(w, "Hello, World!")
}

func main() {
    http.Handle("/", middleware(http.HandlerFunc(handler)))
    http.ListenAndServe(":8080", nil)
}
```

#### **2.2 シンプルなMiddlewareの実装**

このMiddlewareは、リクエストが処理される前後にメッセージを出力します。

- `middleware()`は`http.Handler`を受け取り、新しい `http.Handler`を返す
- `next.ServeHTTP(w, r)`を実行することで、次の処理（エンドポイントのハンドラー）を呼び出す

実行すると、リクエストごとにリクエストの前後でログが表示されます。

---

## 3. 実践的なMiddlewareの例

#### **3.1 ロギングMiddleware**

リクエストの URL・メソッド・処理時間を記録するMiddleware。

```go
package main

import (
    "log"
    "net/http"
    "time"
)

func loggingMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        start := time.Now()
        next.ServeHTTP(w, r)
        duration := time.Since(start)
        log.Printf("%s %s %v", r.Method, r.URL.Path, duration)
    })
}
```

#### **3.2 認証Middleware（JWT）**

JWT（JSON Web Token）を使った認証 Middlewareの例。

```go
package main

import (
    "net/http"
)

func authMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        token := r.Header.Get("Authorization")
        if token != "valid-token" {
            http.Error(w, "Unauthorized", http.StatusUnauthorized)
            return
        }
        next.ServeHTTP(w, r)
    })
}
```

- `Authorization`ヘッダーに`"valid-token"`が含まれている場合のみ許可
- 不正なリクエストは`401 Unauthorized`を返す

#### **3.3 CORS Middleware**

フロントエンド（ReactやVueなど）と連携する際に、CORSを許可する Middleware。

```go
package main

import "net/http"

func corsMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Access-Control-Allow-Origin", "*")
        w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
        w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
        if r.Method == "OPTIONS" {
            w.WriteHeader(http.StatusOK)
            return
        }
        next.ServeHTTP(w, r)
    })
}
```

- すべてのオリジン（`*`）を許可
- `OPTIONS`リクエストに`200 OK`を返すことで、プリフライトリクエストを処理

---

## 4. まとめ

| 項目 | 説明 |
|------|------|
| **Middlewareの役割** | 共通処理（ロギング、認証、CORSなど）を適用する |
| **GoでのMiddlewareの書き方** | `http.Handler`をラップする関数を作成 |
| **実践的なMiddleware** | ロギング・認証・CORSなどの Middlewareを実装 |

Middlewareを組み合わせてAPIの拡張性を向上させることもできたりします。
フロントエンドと連携するようなWebアプリケーションを作成するときには恐らく触れる概念だと思うので、是非検証してみてください！