【Golang】net/httpだけでルーティングを実装する

目次

はじめに

net/httpではルーティングを自前で実装する必要があるため、他のルーティングライブラリを利用した方が便利だと思っていました。

しかし、Go1.22でnet/httpのルーティング機能が強化されたようです。(調査不足で知らなかった)

そこでこの記事では、Go1.22で対応した機能を使いつつ、標準ライブラリでルーティングを実装する簡単なサンプルをまとめます。

Hello, world!

まずはシンプルなHello, world!から。

main.go
package main

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

func HelloHandler(w http.ResponseWriter, r *http.Request) {
    io.WriteString(w, "Hello, world!\n")
}

func main() {
    http.HandleFunc("/hello", HelloHandler)

    if err := http.ListenAndServe(":8080", nil); err != nil {
        log.Fatal(err)
    }
}

サーバーを起動しリクエストを送信すると、Hello, world!が出力されます。

Plaintext
go-sample $ curl http://localhost:8080/hello
Hello, world!

HTTPメソッドの指定

Go1.22から標準ライブラリでHTTPメソッドの指定が可能になっています。

下記はGETメソッドの場合のみHello, world!を出力する例です。

main.go
package main

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

func HelloHandler(w http.ResponseWriter, r *http.Request) {
	  io.WriteString(w, "Hello, world!\n")
}

func main() {
    // GET メソッドを指定
    http.HandleFunc("GET /hello", HelloHandler)

    if err := http.ListenAndServe(":8080", nil); err != nil {
        log.Fatal(err)
    }
}

GETメソッド以外のリクエストは弾かれていることが確認できます。

Plaintext
go-sample $ curl http://localhost:8080/hello -X GET
Hello, world!

go-sample $ curl http://localhost:8080/hello -X POST
Method Not Allowed

go-sample $ curl http://localhost:8080/hello -X PUT 
Method Not Allowed

go-sample $ curl http://localhost:8080/hello -X DELETE
Method Not Allowed

なおGo1.22以前だと、次のように自前でHTTPメソッドに応じた処理を用意する必要がありました。

main.go
package main

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

func HelloHandler(w http.ResponseWriter, r *http.Request) {
    // GET メソッド以外は 405 (Method Not Allowed) を返す
    if r.Method == http.MethodGet {
        io.WriteString(w, "Hello, world!\n")
    } else {
        http.Error(w, "HTTPメソッドが不正です。", http.StatusMethodNotAllowed)
    }
}

func main() {
    // "GET /hello"とは指定できない
    http.HandleFunc("/hello", HelloHandler)
    
    if err := http.ListenAndServe(":8080", nil); err != nil {
        log.Fatal(err)
    }
}

パスパラメータの取得

今度はusers/123のように特定のidをパスに含むケースを考えます。

Go1.22よりパスパラメータの取得もnet/httpのRequest.PathValueで簡単にできるようになりました。

main.go
package main

import (
    "fmt"
    "log"
    "net/http"
    "strconv"
)

func UserHandler(w http.ResponseWriter, r *http.Request) {
   // パスパラメータを取得
  	userIDStr := r.PathValue("id")
  
  	userID, err := strconv.Atoi(userIDStr)
  	if err != nil {
  			http.Error(w, "数値以外のIDは無効です", http.StatusBadRequest)
  			return
  	}
  
  	fmt.Fprintf(w, "ユーザーID: %d\n", userID)
}

func main() {
   // プレースホルダで{id}と定義
  	http.HandleFunc("GET /users/{id}", UserHandler)
  
  	if err := http.ListenAndServe(":8080", nil); err != nil {
  			log.Fatal(err)
  	}
}

idの取得を確認できます。

Plaintext
go-sample $ curl http://localhost:8080/users/123 -X GET
ユーザーID: 123

go-sample $ curl http://localhost:8080/users/aaa -X GET
数値以外のIDは無効です

なおGo1.22以前でパスパラメータを取得する場合、/users/123を”/”区切りで文字列分割したり、正規表現を用いるなどして、強引に123を抽出しなくてはダメだったようです。

クエリパラメータの取得

最後は/users?id=123&age=30のようにクエリパラメータが付与されているケースを考えます。

取得方法は次のとおりです。

main.go
package main

import (
    "fmt"
    "log"
    "net/http"
    "strconv"
)

func UserHandler(w http.ResponseWriter, r *http.Request) {
    // Query メソッドでクエリパラメータの構造体を取得
  	query := r.URL.Query()
  	idStr := query.Get("id")
  	ageStr := query.Get("age")
  
  	id, err := strconv.Atoi(idStr)
  	if err != nil {
  			http.Error(w, "id は数値で指定してください", http.StatusBadRequest)
  			return
  	}
  
  	age, err := strconv.Atoi(ageStr)
  	if err != nil {
  			http.Error(w, "age は数値で指定してください", http.StatusBadRequest)
  			return
  	}
  	fmt.Fprintf(w, "ユーザーID: %d, 年齢: %d\n", id, age)
}

func main() {
  	http.HandleFunc("GET /users", UserHandler)
  
  	if err := http.ListenAndServe(":8080", nil); err != nil {
  		log.Fatal(err)
  	}
}

クエリパラメータに関してはGo1.22以前からURL.Query()による取得が可能だったようです。

まとめ

Go1.22でnet/httpのルーティング機能が強化されたことで、他のライブラリを使わずともかなり便利にルーティングを実装できることがわかりました。

Goを学び始めて日が浅いため、この調子でまずは標準パッケージの理解を少しずつ深めていけたらと思います。

記事の内容について誤りがあればコメントにて教えていただけると幸いです。

参考資料

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

未経験でSESから従業員300名以上の自社開発企業に転職しました。業務や個人開発で直面した問題や、転職・学習の経験を発信していきます。

コメント

コメントする

目次