Menu
Coddy logo textTech

http.Handler インターフェース

CoddyのGOジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 77/107。

http.Handler インターフェースは、Goのウェブサーバーアーキテクチャの基盤です。これはHTTPリクエストがどのように処理されるかを定義しており、これを実装する任意の型はウェブ要求を処理することができます。

インターフェースは非常にシンプルです:

type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}

ServeHTTP メソッドを持つ任意の型は、HTTP リクエストを処理できます。以下はカスタムハンドラーの例です:

type GreetHandler struct {
    Greeting string
}

func (h GreetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "%s, visitor!", h.Greeting)
}

このハンドラーは、サーバーで直接使用できます:

handler := GreetHandler{Greeting: "Welcome"}
http.Handle("/greet", handler)

より単純なケースでは、Goは通常の関数をハンドラーに変換できる型である http.HandlerFunc を提供しています。

func hello(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello!")
}

http.Handle("/hello", http.HandlerFunc(hello))

このインターフェースの強力さは、ハンドラーが他のハンドラーをラップできることに気づいたときに明らかになります。これにより、元のハンドラーのロジックを変更することなく、ロギング、認証、またはその他の横断的な関心事を追加するミドルウェアパターンが可能になります。

challenge icon

チャレンジ

簡単

Webリクエストがどのように処理されるかをシミュレートする、シンプルなHTTPハンドラーシステムを構築しましょう!この環境では実際のHTTPサーバーを実行できないため、http.Handlerインターフェースを実装するハンドラーを作成し、モックのリクエスト/レスポンスオブジェクトを使用してそれらがどのようにリクエストを処理するかを実演します。

コードは2つのファイルに分けて構成します:

  • handlers.go: カスタムHTTPハンドラーを定義します。

    HTTPレスポンスに書き込まれる内容をキャプチャするMockResponseWriter構造体を作成します。これはレスポンスボディを文字列として保存し、データをボディに追加するWrite(data []byte) (int, error)メソッドを実装する必要があります。また、蓄積されたレスポンスを取得するためのBody() stringメソッドを追加してください。

    HTTPリクエストをシミュレートするために、PathMethodの文字列フィールドを持つMockRequest構造体を作成します。

    次に、http.Handlerインターフェースのパターン(*MockResponseWriter*MockRequestを受け取るServeHTTPメソッドを持つ)を実装する2つのハンドラー構造体を作成します:

    • WelcomeHandlerMessageフィールドを持つ) - メッセージの後にリクエストパスを続けて書き込みます。
    • MethodHandler - リクエストメソッドに基づいて異なるレスポンスを書き込みます:GETの場合は"Fetching data"、POSTの場合は"Creating resource"、それ以外の場合は"Method not supported"とします。
  • main.go: ハンドラーを通じてリクエストを処理します。

    ハンドラータイプ(welcomeまたはmethod)を読み取り、次にリクエストの詳細を読み取ります。welcomeハンドラーの場合は、ウェルカムメッセージも読み取ります。

    適切なハンドラーを作成し、モックリクエストを構築して、ServeHTTPを呼び出して処理します。レスポンスボディをプリントしてください。

以下の入力が提供されます:

  • 1行目:ハンドラータイプ(welcomeまたはmethod
  • 2行目:リクエストパス
  • 3行目:リクエストメソッド
  • 4行目(welcomeの場合のみ):ウェルカムメッセージ

例えば、以下が与えられた場合:

welcome
/home
GET
Hello from

出力は以下のようになります:

Hello from /home

また、以下が与えられた場合:

method
/api/users
POST

出力は以下のようになります:

Creating resource

また、以下が与えられた場合:

method
/api/data
GET

出力は以下のようになります:

Fetching data

また、以下が与えられた場合:

method
/api/items
DELETE

出力は以下のようになります:

Method not supported

このチャレンジは、http.Handlerインターフェースの核心的な概念、つまりServeHTTPメソッドを持つ任意の型がリクエストを処理できることを示しています。実際のアプリケーションでは、http.ResponseWriter*http.RequestはGoの標準ライブラリから提供されますが、ハンドラーを実装するパターンは全く同じです。

チートシート

http.Handler インターフェースは、Goのウェブサーバーアーキテクチャの基盤です:

type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}

ServeHTTP メソッドを持つ任意の型は、HTTPリクエストを処理できます:

type GreetHandler struct {
    Greeting string
}

func (h GreetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "%s, visitor!", h.Greeting)
}

サーバーにハンドラーを登録します:

handler := GreetHandler{Greeting: "Welcome"}
http.Handle("/greet", handler)

より単純なケースでは、http.HandlerFunc を使用して関数をハンドラーに変換します:

func hello(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello!")
}

http.Handle("/hello", http.HandlerFunc(hello))

ハンドラーは他のハンドラーをラップすることができ、ロギング、認証、またはその他の横断的な関心事のためのミドルウェアパターンを可能にします。

自分で試してみよう

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	// ハンドラーのタイプを読み込む
	scanner.Scan()
	handlerType := scanner.Text()
	
	// リクエストパスを読み込む
	scanner.Scan()
	path := scanner.Text()
	
	// リクエストメソッドを読み込む
	scanner.Scan()
	method := scanner.Text()
	
	// モックリクエストを作成
	request := &MockRequest{
		Path:   path,
		Method: method,
	}
	
	// モックレスポンスライターを作成
	response := &MockResponseWriter{}
	
	// TODO: handlerTypeに基づいて、適切なハンドラーを作成する
	// handlerTypeが "welcome" の場合は、ウェルカムメッセージを読み込んで WelcomeHandler を作成する
	// handlerTypeが "method" の場合は、MethodHandler を作成する
	// ハンドラーの ServeHTTP を response と request を引数にして呼び出す
	
	if handlerType == "welcome" {
		scanner.Scan()
		message := scanner.Text()
		// TODO: メッセージを使用して WelcomeHandler を作成し、ServeHTTP を呼び出す
		_ = message // 実装時にこの行を削除してください
	} else if handlerType == "method" {
		// TODO: MethodHandler を作成し、ServeHTTP を呼び出す
	}
	
	// レスポンスボディを出力
	fmt.Println(response.Body())
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン