🐣

Ginを理解するためにnet/httpを触るやつ 1

2021/10/17に公開

はじめに

Web系の事業会社に新卒入社して半年ほど経ちました。

3か月前に配属されGinを触り始めたのですが、業務ではビジネスロジックの実装が中心なため基礎的な部分が全然理解できていません。

さすがにそろそろGinがnet/httpのラッパーとして何をやっているのか気になってきたので、それぞれ同じ機能のサーバを書いてみて比較しながら理解してみたいと思います。

環境

OS: Ubuntu 20.04.2 LTS (WSL2)

Go 1.16

Gin 1.7.4

制作物

localhost:3000/public/helloへのGETリクエストで簡単なjsonを返すAPIサーバを実装してみました。

今回の目的からは若干逸れますが、ディレクトリ構成はこちらの標準レイアウトを参考にしています。

Ginでの実装

リポジトリ:https://github.com/imsugeno/gin

ディレクトリ構成

.
├── README.md
├── cmd
│   └── main.go
├── go.mod
├── go.sum
└── internal
    └── handler
        ├── handler.go
        └── route_hello.go
main.go
package main

import (
	"github.com/imsugeno/gin/internal/handler"
)

func main() {
	r := handler.NewGinEngin()
	r.Run(":3000")
}
handler.go
package handler

import (
	"github.com/gin-gonic/gin"
)

func NewGinEngin() *gin.Engine {
	r := gin.Default()

	public := r.Group("/public")
	{
		bindRouteOfHello(public.Group("/hello"))
	}
	return r
}
route_hello.go
package handler

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

func bindRouteOfHello(r *gin.RouterGroup) {
	r.GET("", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"message": "hello world",
		})
	})
}

net/httpでの実装

リポジトリ:https://github.com/imsugeno/net-http

ディレクトリ構成

.
├── README.md
├── cmd
│   └── main.go
├── go.mod
└── internal
    └── handler
        └── route_public.go
main.go
package main

import (
	"net/http"

	"github.com/imsugeno/net-http/internal/handler"
)

func main() {
	mux := http.NewServeMux()

	mux.HandleFunc("/public/hello", handler.Hello)
	http.ListenAndServe(":3000", mux)
}
route_public.go
package handler

import (
	"encoding/json"
	"net/http"
)

func Hello(w http.ResponseWriter, r *http.Request) {
	message := map[string]string{"message": "hello world"}
	jsonMessage, err := json.Marshal(message)
	if err != nil {
		panic(err.Error())
	}
	w.Write(jsonMessage)
}

次回以降の追及点

深堀りするのは次回以降に回して、今回湧いた疑問点を書き起こしておこうと思います。

  • Ginでのルーティンググループはどのように実装されているの?
    gin.RouterGroup/public以下のルーティングをまとめているのですが、仕組みがよくわかっていないのでnet/httpでは実装できず、フルパス/public/helloでハンドラ関数に紐づける実装しかできませんでした。

この辺りはGinがうまいことやってくれてる部分だと思うので、これからの投稿のネタにしたいと思います。

  • Ginではどうやってリクエストメソッドに応じたルーティングをしてるの?
    GETリクエストでjsonを返すと冒頭で言ったものの、上のnet-httpリポジトリの実装だとHTTPリクエストメソッドに応じたルーティングはされておらず、POSTでもPUTでも200 OKでレスポンスが返ります。

こちらもgin.RouterGroupがうまくやってくれてるようなので、ルーティングの話題として理解していこうと思います。

  • gin.Contextの仕事
    net/httpでハンドラやハンドラ関数に渡すhttp.ResponseWriter*http.Requestを構造体として持っているのはわかるのですが、それ以外にフィールドで持っているqueryCacheやらはなんなんだろうか...

  • そもそもgin.Engineって何?
    何?

GitHubで編集を提案

Discussion