📖

Gin入門:最小のWeb APIを作りながら内部実装を理解する

に公開

gin入門してみた

今回はRaspberry Piで自作サーバーを作る予定があり、
そのバックエンドAPIをGinで実装してみようと思います!
GinはGoを使った高速なWebフレームワークです。
「最小のAPI」を作りながら内部実装も軽く深掘ります。

What is Gin?

GinはGolangで書かれたウェブフレームワークです。MartiniライクなAPIを備えながら、Martiniの最大40倍の高速パフォーマンスを実現します。パフォーマンスと生産性を重視するなら、Ginが最適です。
と公式に紹介されています。

公式ページ

早速gin導入してみよう

プロジェクト作成

mkdir Project-go
cd Project-go

初期化して Gin をインストール

go mod init Project-go
go get github.com/gin-gonic/gin

最小のAPIを作ってみた

package main

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

func main() {
    router := gin.Default()

    router.GET("/health", func(c *gin.Context) {
        c.JSON(http.StatusOK, gin.H{
            "status": "ok",
        })
    })

    router.Run(":8080")
}

コードの解説

gin.Default()

Gin のルーター(リクエストの入り口)を作って、
便利なミドルウェアを自動で付けてくれる

実際のソースコード

func Default(opts ...OptionFunc) *Engine {
	debugPrintWARNINGDefault()

    // gin.New()でエンジンの本体を作成
	engine := New()

    // ここでLoggerとRecoveryを追加
	engine.Use(Logger(), Recovery())
	return engine.With(opts...)
}

構造はこうなっています

gin.Default()
   │
   ▼
gin.New()    → Ginの内部構造(Engine)を作る
   │
   ▼
Logger()     → アクセスログ出すミドルウェア追加
Recovery()   → panic発生でもサーバー落とさない

New()の中身

func New(opts ...OptionFunc) *Engine {
	debugPrintWARNINGNew()
	engine := &Engine{
		RouterGroup: RouterGroup{
			Handlers: nil,
			basePath: "/",
			root:     true,
		},
		FuncMap:                template.FuncMap{},
		RedirectTrailingSlash:  true,
		RedirectFixedPath:      false,
		HandleMethodNotAllowed: false,
		ForwardedByClientIP:    true,
		RemoteIPHeaders:        []string{"X-Forwarded-For", "X-Real-IP"},
		TrustedPlatform:        defaultPlatform,
		UseRawPath:             false,
		RemoveExtraSlash:       false,
		UnescapePathValues:     true,
		MaxMultipartMemory:     defaultMultipartMemory,
		trees:                  make(methodTrees, 0, 9),
		delims:                 render.Delims{Left: "{{", Right: "}}"},
		secureJSONPrefix:       "while(1);",
		trustedProxies:         []string{"0.0.0.0/0", "::/0"},
		trustedCIDRs:           defaultTrustedCIDRs,
	}
	engine.engine = engine
	engine.pool.New = func() any {
		return engine.allocateContext(engine.maxParams)
	}
	return engine.With(opts...)
}

色々書いてありますがAIにまとめてもらいました、それがこちら

一言で言うと

gin.New() は、最小限の安全で高速なHTTPエンジンを作る
その上で Default() が便利機能を足す
New() の中身は Gin の本体 = Engine の初期化処理です

まあgin.Default()を呼び出してあげればHTTPエンジンが作られるということです

ではなぜ最初にルーターを作成しないといけないのか?

クライアントからのリクエストを受け取って処理したり処理を振り分けたりす
るための入口、受付係のような役割を担っています。
これのおかげでサーバーにリクエストが渡った時に処理ができてブラウザーに処理結果を
返せるようになります。
なので一番最初に作っておきましょう!!

次はこちら

router.GET("/health", func(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{
		"status": "ok",
	})
})

ここのブロックにHTTP通信の本質が詰まっています

構造はこうなっている

router.GET(パス, ハンドラー関数)

言葉 意味
GET HTTPメソッド:ブラウザやcurlが使う命令
"/health" URLパス:どこにアクセスしたか
func(c *gin.Context) リクエストを処理する関数(Handler)

router.GET("/health", ....

「GETリクエストで /health に来たら、この処理を実行してね」

func(c *gin.Context)

→ リクエストとレスポンスを管理する Context が入ってくる
Contextって何?
ヘッダー情報
JSONの読み取り
クエリ・パラメータ
レスポンスの書き込み
すべて Context 経由で操作できる
→ Gin の一番重要な型
ちなみにcはgin.Contextのポインタです。JSONメソッドにcがレシーバとして
設定されているからcでJSONメソッドが呼び出せます

c.JSON(http.StatusOK, gin.H{...})

レスポンスを JSON で返す処理
c.JSON
JSON形式でレスポンス返す

http.StatusOK
HTTPステータス(200)

gin.H{...}
JSONとして組み立てるマップ

router.Run(":8080")

サーバー起動(:8080で待ち受け)

実際に接続してみる

ターミナルで

curl http://localhost:8080/health

結果

{"status":"ok"}

これができたら成功です!!

まとめ

・Gin を使うと HTTP API が簡単に作れる
・シンプルな構文なので初心者にもおすすめ

次回

次回はこのAPIにTodo機能を追加して
POST/DELETEなどのREST APIを実装していきます!
ラズパイにデプロイしてCloudflare Tunnelで公開するところまでやる予定です(頑張る)

Discussion