Goでサーバ処理を追加する#
Goでは、HTTPハンドラを使用してWebリクエストを処理します。標準ライブラリのnet/http
パッケージやGinなどのフレームワークを使うことで、さまざまなエンドポイントと処理を簡単に実装できます。
WebアプリケーションではURLのパスに紐づけて処理をすることが多いです。
URLとは、サイトを表示するときにブラウザに指定する文字列のことで、例えば https://ukiuni.com/hello のような文字列です。 {通信方式}://{サーバ名}/{パス} のような形式で出来上がっています。
このパスに、処理を紐付けることで、1つのサーバに色々な処理を依頼できるようになっています。
前提#
もし、Goプロジェクトが手元になければ、こちらの手順でGoプロジェクトを用意してください。こちらでも簡単なハンドラを作成していますが、Goの重要な処理なので、こちらで改めて説明しています。
標準パッケージを使用したハンドラとルーティングの追加#
main.go
ファイルを更新して、新しいハンドラ関数を追加します:
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"time"
)
// Message はJSONレスポンス用の構造体です
type Message struct {
Text string `json:"text"`
}
// OrderMessage は注文レスポンス用の構造体です
type OrderMessage struct {
Message string `json:"message"`
Time string `json:"time"`
}
// helloHandler は/helloエンドポイントを処理します
func helloHandler(w http.ResponseWriter, r *http.Request) {
message := Message{
Text: "こんにちは!",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(message)
}
// orderOudonHandler は/oudonエンドポイントを処理します
func orderOudonHandler(w http.ResponseWriter, r *http.Request) {
// 現在時刻を文字列に変換
currentTime := time.Now().Unix()
timeStr := fmt.Sprintf("%d", currentTime)
orderMessage := OrderMessage{
Message: "おうどんください。",
Time: timeStr,
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(orderMessage)
}
func main() {
// ハンドラを設定
http.HandleFunc("/hello", helloHandler)
http.HandleFunc("/oudon", orderOudonHandler)
// サーバーを起動
fmt.Println("サーバーを起動します: http://localhost:8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
この例では:
OrderMessage
構造体を定義しています。これはJSON形式で応答するためのデータ構造です。/oudon
パスに対応するorderOudonHandler
関数を定義しています。- メイン関数内で
http.HandleFunc()
を使用してURLパスとハンドラ関数を関連付けています。
注意点:
- Goでは、http.HandleFunc()
を使用してルートを定義します。
- レスポンスを返す際にはhttp.ResponseWriter
インターフェースを使用します。
- JSONエンコードにはjson.NewEncoder
を使用します。
パラメータを受け取るハンドラの追加#
URLクエリパラメータを受け取るハンドラも実装してみましょう:
// greetHandler は/greetエンドポイントを処理し、クエリパラメータを受け取ります
func greetHandler(w http.ResponseWriter, r *http.Request) {
// URLクエリパラメータを取得
name := r.URL.Query().Get("name")
if name == "" {
name = "ゲスト"
}
response := struct {
Message string `json:"message"`
}{
Message: fmt.Sprintf("こんにちは、%sさん!", name),
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
// main関数内に以下を追加
// http.HandleFunc("/greet", greetHandler)
この例をmain.go
に追加して、main
関数内のhttp.HandleFunc("/greet", greetHandler)
を追加してください:
func main() {
// ハンドラを設定
http.HandleFunc("/hello", helloHandler)
http.HandleFunc("/oudon", orderOudonHandler)
http.HandleFunc("/greet", greetHandler)
// サーバーを起動
fmt.Println("サーバーを起動します: http://localhost:8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
サーバーを起動すると、http://localhost:8080/greet?name=田中
のようなURLでアクセスできるようになります。
Ginフレームワークを使用したバージョン#
Ginフレームワークを使うとより簡潔で読みやすいコードを書くことができます。main.go
を更新してGinバージョンを実装しましょう:
package main
import (
"fmt"
"net/http"
"time"
"github.com/gin-gonic/gin"
)
// Message はJSONレスポンス用の構造体です
type Message struct {
Text string `json:"text"`
}
// OrderMessage は注文レスポンス用の構造体です
type OrderMessage struct {
Message string `json:"message"`
Time string `json:"time"`
}
func main() {
// Ginルーターを初期化
r := gin.Default()
// /helloエンドポイント
r.GET("/hello", func(c *gin.Context) {
message := Message{
Text: "こんにちは!",
}
c.JSON(http.StatusOK, message)
})
// /oudonエンドポイント
r.GET("/oudon", func(c *gin.Context) {
currentTime := time.Now().Unix()
timeStr := fmt.Sprintf("%d", currentTime)
orderMessage := OrderMessage{
Message: "おうどんください。",
Time: timeStr,
}
c.JSON(http.StatusOK, orderMessage)
})
// /greetエンドポイント - クエリパラメータの使用
r.GET("/greet", func(c *gin.Context) {
name := c.DefaultQuery("name", "ゲスト")
response := struct {
Message string `json:"message"`
}{
Message: fmt.Sprintf("こんにちは、%sさん!", name),
}
c.JSON(http.StatusOK, response)
})
// POSTリクエストを処理するエンドポイント
r.POST("/users", func(c *gin.Context) {
var user struct {
Username string `json:"username" binding:"required"`
Email string `json:"email" binding:"required"`
}
// リクエストボディをバインド
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// ユーザーデータを処理...
c.JSON(http.StatusCreated, gin.H{"message": fmt.Sprintf("ユーザー %s が作成されました", user.Username)})
})
// サーバーを起動
fmt.Println("サーバーを起動します: http://localhost:8080")
r.Run(":8080") // listen and serve on 0.0.0.0:8080
}
Ginフレームワークを使用する主な利点:
- より簡潔なルーティング定義(
r.GET()
,r.POST()
など) - パスパラメータとクエリパラメータの簡単な取得(
c.Param()
,c.Query()
) - リクエストボディの自動バインディング(
c.ShouldBindJSON()
) - ミドルウェアの簡単な使用
- グループルーティングの管理がしやすい
HTTPメソッドとルーティンググループ#
Ginでは、さまざまなHTTPメソッドに対応するメソッドが用意されています:
r.GET("/resource") // GETリクエスト
r.POST("/resource") // POSTリクエスト
r.PUT("/resource") // PUTリクエスト
r.DELETE("/resource") // DELETEリクエスト
また、ルーティンググループを使用してルートをまとめることができます:
// APIのバージョン1のグループ
v1 := r.Group("/api/v1")
{
v1.GET("/users", getUsers)
v1.GET("/users/:id", getUserByID)
v1.POST("/users", createUser)
}
// APIのバージョン2のグループ
v2 := r.Group("/api/v2")
{
v2.GET("/products", getProducts)
v2.POST("/products", createProduct)
}
このようにグループ化することで、共通のパスプレフィックスを持つルートを整理できます。
サーバを起動してみる#
これで、Goでのサーバー処理の基本が完成しました。サーバーを起動してみましょう:
go run main.go
ブラウザで以下のURLにアクセスしてみてください:
- http://localhost:8080/hello
- http://localhost:8080/oudon
- http://localhost:8080/greet?name=あなたの名前
適切なJSONレスポンスが表示されれば成功です!
次は、Goでデータベースを扱ってみましょう。