Go × Gin 基礎編:高速APIサーバーの作り方を徹底解説

  • golang
    golang
  • gin
    gin
2023/11/23に公開

はじめに

Go言語はシンプルで高速な処理能力を誇り、WebサービスやAPI開発において非常に頼もしい存在です。そのGoの強みを最大限に引き出してくれるのが、軽量かつ高性能なWebフレームワーク「Gin」です。

本記事では、Go × Ginの魅力と基礎的な使い方を、初心者でも取り組みやすいように順序立てて解説します。インストールからHello Worldの作成、リクエスト・レスポンスの基本、そしてミドルウェアの活用まで、すぐに試せる具体例を交えながら進めていきます。

「高速でシンプルなAPIサーバーを作りたい」と思っている方にとって、この記事が役立つガイドになることを願っています。さあ、一緒にGinの世界をのぞいてみましょう。

Go + Ginを選ぶ理由

WebアプリケーションやAPIサーバーを作る際、使用する言語やフレームワークは非常に重要です。ここで、GoとGinを選ぶ理由を整理しておきます。

1️⃣ Goの魅力

  • 高いパフォーマンス:Goはコンパイル言語であり、軽快で高速な実行が可能です。
  • シンプルな文法:最小限の記法で堅牢なコードを書けるため、学習コストが抑えられます。
  • 並行処理に強い:GoroutineやChannelを活用することで、スケーラブルな処理が実現しやすいです。

2️⃣ Ginの強み

  • 驚異的な速度:Ginは「極めて高速なWebフレームワーク」として知られています。
  • 豊富な機能:ルーティング、ミドルウェア、JSONハンドリングなど、APIサーバーに必要な機能が網羅されています。
  • シンプルなAPI設計:わかりやすいAPIで、すぐに実践的な開発に取りかかれます。

3️⃣ Go × Ginの相性の良さ

GoのシンプルさとGinのスピード・機能性は非常に相性が良く、パフォーマンスと保守性を両立したAPIサーバー構築を支えてくれます。
この記事では、この強力な組み合わせを活かし、実際にAPIサーバーを作る流れを丁寧に解説していきます。次は、まずGinを動かすところから始めていきます。

Ginのインストールと初期設定

ここでは、Ginをプロジェクトにインストールし、最小限のサーバーを動かすところまでを進めていきます。

Goのバージョン確認

まずは、Goのバージョンを確認します。GinはGo 1.18以降を推奨しているため、以下のコマンドで現在のGoバージョンを確認しておきます。

go version

例)

go version go1.23.0 darwin/arm64

プロジェクトディレクトリの作成

新しいプロジェクト用のディレクトリを作ります。例として my-gin-app という名前のディレクトリを作成します。

mkdir go-gin-basic-guide
cd go-gin-basic-guide

Goモジュールの初期化

まだGoモジュールを初期化していない場合は、以下を実行します。

go mod init go-gin-basic-guide

Ginのインストール

Ginをインストールします。

go get -u github.com/gin-gonic/gin

Image from Gyazo

最小限のサーバーを作成

main.goを作成し、以下の内容を書きます。

main.go
package main

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

func main() {
	r := gin.Default()
	r.GET("/ping", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "pong",
		})
	})
	r.Run() // デフォルトで :8080 ポート
}

サーバーを起動する

以下のコマンドでサーバーを起動します。

go run main.go

Image from Gyazo

ブラウザやcurlで http://localhost:8080/ping にアクセスし、JSONレスポンスが表示されることを確認します。

curl http://localhost:8080/ping

Image from Gyazo

これで、Ginを動かすための基本的な準備は整いました。次は、Ginの基本構造をもう少し深掘りしていきます。

補足: Airの導入でホットリロードを実現する

開発中にコードを変更するたびに go run を手動で実行するのは面倒です。そこで、air を導入してホットリロードを可能にします。

以下のコマンドで air をインストールします。

go install github.com/air-verse/air@latest

air.air.toml という設定ファイルを利用できます。プロジェクトルートに以下の内容で作成します。

# .air.toml
root = "."
tmp_dir = "tmp"

[build]
  cmd = "go build -o ./tmp/main ."
  bin = "tmp/main"
  include_ext = ["go"]
  exclude_dir = ["tmp", "vendor"]

[log]
  time = true
項目 意味
root 監視するディレクトリのルート
tmp_dir ビルド成果物の置き場
[build] ビルドと実行の設定
cmd ビルドコマンド(ここではGoのバイナリを tmp/main にビルド)
bin 実行するバイナリファイルのパス
include_ext 監視するファイルの拡張子
exclude_dir 監視対象から除外するディレクトリ

以下のコマンドを実行すると、air がソースコードの変更を監視し、即座に再起動してくれます。

air

Image from Gyazo

試しにURLのパスを/ping -> /pongに変更してみます。

main.go
func main() {
	r := gin.Default()
-	r.GET("/ping", func(c *gin.Context) {
+	r.GET("/pong", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "pong",
		})
	})
	r.Run() // デフォルトで :8080 ポート
}

すると、/pongでレスポンスが返って来ることを確認できます。

curl http://localhost:8080/pong

動作確認が終わったら元に戻しておきます。

Ginの基本構造を理解する

Ginのアプリケーションは、ルーター、ハンドラ、コンテキストを中心に構成されます。ここでは、それぞれの役割と仕組みを詳しく整理し、実際にリクエストを変更しながら動作確認できる例も加えます。

ルーター(Router)

Ginのエントリーポイントは「ルーター」です。gin.Default() を使うと、ロガーやリカバリーミドルウェアがあらかじめ組み込まれたルーターを簡単に初期化できます。

r := gin.Default()

ハンドラ(Handler)

ルーターに登録したエンドポイントに対応するのが、ハンドラ関数です。これは、HTTPリクエストを受け取ってレスポンスを返す処理です。

例えば以下では、/ping というパスにアクセスしたときに「pong」というJSONレスポンスを返します。

r.GET("/ping", func(c *gin.Context) {
    c.JSON(200, gin.H{"message": "pong"})
})

ここで /ping はURLのパス部分にあたります。ブラウザやcurlで http://localhost:8080/ping にアクセスして、動作を確認します。

コンテキスト(Context)

*gin.Context は、リクエストやレスポンスに関する情報を扱うための便利な構造体です。

例えば、以下のようにクエリパラメータを取得できます。

main.go
func main() {
	r := gin.Default()
	r.GET("/ping", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "pong",
		})
	})
+	r.GET("/hello", func(c *gin.Context) {
+		name := c.Query("name") // ?name=値 で取得
+		c.JSON(200, gin.H{"message": "Hello, " + name})
+	})
	r.Run() // デフォルトで :8080 ポート
}
curl 'http://localhost:8080/hello?name=Gopher'

レスポンスは以下のようになります。

{"message": "Hello, Gopher"}

クエリパラメータを変えて再リクエストすれば、レスポンスも変わることを確認できます。

グルーピング(Grouping)

エンドポイントが多くなると、共通のパスをまとめて管理したくなります。Ginのグルーピングを使うと、パスの共通部分をまとめることができます。

以下の例では、/api という共通パスをグルーピングし、その中で GET /api/usersPOST /api/users を定義しています。

main.go
func main() {
	r := gin.Default()
	r.GET("/ping", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "pong",
		})
	})
	r.GET("/hello", func(c *gin.Context) {
		name := c.Query("name") // ?name=値 で取得
		c.JSON(200, gin.H{"message": "Hello, " + name})
	})
+	api := r.Group("/api")
+	{
+		api.GET("/users", func(c *gin.Context) {
+			c.JSON(200, gin.H{"message": "GET /api/users"})
+		})
+
+		api.POST("/users", func(c *gin.Context) {
+			c.JSON(200, gin.H{"message": "POST /api/users"})
+		})
+	}
	r.Run() // デフォルトで :8080 ポート
}

以下のURLにアクセスすると、それぞれのエンドポイントが正しく動作していることを確認できます。

curl http://localhost:8080/api/users
curl -X POST http://localhost:8080/api/users

リクエスト処理の基本

ここでは、Ginを使ったリクエスト処理の基本を整理します。
実際にパラメータを取得し、レスポンスを返す方法を動作確認しながら見ていきます。

パスパラメータの取得

パスに埋め込まれた値を取得するには、:param という形でルーティングを定義します。

main.go
+ r.GET("/users/:id", func(c *gin.Context) {
+     id := c.Param("id")
+     c.JSON(200, gin.H{"user_id": id})
+ })

以下のURLにアクセスします。

curl http://localhost:8080/users/123

レスポンス

{"user_id": "123"}

クエリパラメータの取得

クエリパラメータ(?key=value の形)を取得するには、c.Query を使います。

main.go
+ r.GET("/search", func(c *gin.Context) {
+     keyword := c.Query("q")
+     c.JSON(200, gin.H{"query": keyword})
+ })

以下のURLにアクセスします。

curl 'http://localhost:8080/search?q=Gin'

レスポンス

{"query": "Gin"}

クエリパラメータを変えると、レスポンスが動的に変わることを確認できます。

フォームパラメータの取得(POST)

フォームから送られるデータは c.PostForm で取得します。

main.go
+ r.POST("/submit", func(c *gin.Context) {
+     name := c.PostForm("name")
+     c.JSON(200, gin.H{"submitted_name": name})
+ })

curlでPOSTリクエストを送ります。

curl -X POST -d "name=Gopher" http://localhost:8080/submit

レスポンス

{"submitted_name": "Gopher"}

JSONリクエストの取得

クライアントからJSON形式でデータが送られてくる場合、c.BindJSON で構造体にバインドします。

main.go
+ type User struct {
+     Name string `json:"name"`
+     Age  int    `json:"age"`
+ }

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

※一部省略

+ r.POST("/json", func(c *gin.Context) {
+		var user User
+		if err := c.BindJSON(&user); err != nil {
+			c.JSON(400, gin.H{"error": err.Error()})
+			return
+		}
+		c.JSON(200, gin.H{"name": user.Name, "age": user.Age})
+	})
	r.Run() // デフォルトで :8080 ポート
}

curlでJSONを送ります。

curl -X POST -H "Content-Type: application/json" -d '{"name":"Gopher","age":5}' http://localhost:8080/json

レスポンス

{"name": "Gopher", "age": 5}

まとめ

リクエスト処理の基本として、以下のポイントを押さえました。

✅ パスパラメータ: c.Param
✅ クエリパラメータ: c.Query
✅ フォームパラメータ: c.PostForm
✅ JSONリクエスト: c.BindJSON

これらを組み合わせることで、様々なAPIリクエストを柔軟に受け取れます。

次は、レスポンスの書き方を見ていきます。

レスポンスの書き方

ここでは、Ginを使ったレスポンスの書き方を整理します。
APIサーバーとして最も重要な「クライアントに何を返すか」を明確にしていきます。

JSONレスポンス

APIではJSON形式のレスポンスを返すことが一般的です。c.JSON を使って以下のように返します。

r.GET("/json", func(c *gin.Context) {
    c.JSON(200, gin.H{
        "message": "Hello, Gin!",
    })
})
  • 第1引数: HTTPステータスコード(例: 200)
  • 第2引数: 返すJSONデータ(map[string]interface{} や構造体)

文字列レスポンス

テキストを直接返す場合は、c.String を使います。

r.GET("/text", func(c *gin.Context) {
    c.String(200, "This is a plain text response.")
})

シンプルなメッセージの返却に便利です。

HTMLレスポンス

HTMLを返す際には c.HTML を使います。
LoadHTMLGlob でテンプレートを読み込み、HTMLを返す例です。

main.go
+ r.LoadHTMLGlob("templates/*")
+ r.GET("/html", func(c *gin.Context) {
+     c.HTML(200, "index.tmpl", gin.H{"title": "Hello, HTML!"})
+ })

以下のようなディレクトリ構成にします。

my-gin-app/
├── main.go
└── templates/
    └── index.tmpl

templates/index.tmpl のサンプル:

<!DOCTYPE html>
<html>
<head>
  <title>{{ .title }}</title>
</head>
<body>
  <h1>{{ .title }}</h1>
  <p>This is a sample HTML response rendered by Gin.</p>
</body>
</html>

ブラウザ上で Hello, HTML! という見出しと本文が表示されます。

Image from Gyazo

まとめ

Ginを使ったレスポンスの書き方として、以下のポイントを押さえました。

✅ JSON: c.JSON
✅ 文字列: c.String
✅ HTML: c.HTML
✅ ステータスコードのみ: c.Status
✅ 統一的なエラーレスポンス: 構造体を定義して返す

これらを使い分けることで、APIの設計・運用がスムーズになります。

次は、Ginのミドルウェアの活用方法を見ていきます。

ミドルウェアの活用

Ginでは、ミドルウェアを使うことでリクエスト前後に共通の処理を差し込むことができます。
ここでは、標準で用意されているミドルウェアや、自作のミドルウェアを導入する方法を整理します。

組み込みミドルウェア

Ginには便利な組み込みミドルウェアがいくつかあります。代表的なものを紹介します。

ロガー(Logger)
リクエストをログ出力するミドルウェアです。

r := gin.New()
r.Use(gin.Logger())

gin.Default() にはすでにロガーが含まれているため、改めて追加する必要はありません。

APIにアクセスするとログがコンソールに表示されます。

Image from Gyazo

リカバリー(Recovery)
パニックが発生してもサーバーを落とさず、500エラーレスポンスを返すミドルウェアです。

r.Use(gin.Recovery())

こちらも gin.Default() に含まれています。

自作ミドルウェアの作り方

共通の前処理や後処理を行いたい場合は、自作のミドルウェアを作成できます。

以下は、リクエストが来るたびに「Before request...」を表示する簡単な例です。

main.go
+ func MyCustomMiddleware() gin.HandlerFunc {
+ 	return func(c *gin.Context) {
+ 		println("Before request...")
+ 		c.Next()
+ 		println("After request...")
+ 	}
+ }

func main() {
	r := gin.Default()
+ 	r.Use(MyCustomMiddleware())

APIにリクエストを送ると、「Before request...」「After request...」と表示されていることが確認できます。

Image from Gyazo

グローバルに適用するのではなく、特定のルートだけにミドルウェアを設定することもできます。

main.go
func main() {
	r := gin.Default()
- 	r.Use(MyCustomMiddleware())

※一部省略

+	r.GET("/special", MyCustomMiddleware(), func(c *gin.Context) {
+		c.JSON(200, gin.H{"message": "This route uses a custom middleware."})
+	})

	r.Run() // デフォルトで :8080 ポート
}

特定のルートだけ「Before request...」「After request...」と表示されていることが確認できます。

Image from Gyazo

さいごに

ここまで、Ginを使ったGoのAPIサーバー開発の基礎を一通り見てきました。
実際にコードを書いて動かしながら学ぶ中で、以下のポイントが整理できたかと思います。

✅ Ginの基本構造(ルーター・ハンドラ・コンテキスト)
✅ 各種リクエストパラメータの取得方法
✅ JSONやテキスト、HTMLレスポンスの書き方
✅ ミドルウェアの活用方法と管理

これらはすべて、API開発の基盤になる考え方です。小さな機能の積み重ねが、将来の大きなシステムにつながります。

次のステップへ

今回学んだ基礎知識をベースに、次はより実践的な応用編へ進めます。

  • 認証・バリデーションの実装
  • Ginのテスト手法
  • 本番運用のポイント
  • スケーラブルなアーキテクチャの考え方 など…

https://shinagawa-web.com/blogs/go-gin-advanced-guide

Xでシェア
Facebookでシェア
LinkedInでシェア

記事に関するお問い合わせ📝

記事の内容に関するご質問、ご意見などは、下記よりお気軽にお問い合わせください。
ご質問フォームへ

技術支援などお仕事に関するお問い合わせ📄

技術支援やお仕事のご依頼に関するお問い合わせは、下記よりお気軽にお問い合わせください。
お問い合わせフォームへ

関連する技術ブログ

弊社の技術支援サービス

お問い合わせ

経営と現場をつなぐ“共創型”の技術支援。
成果に直結するチーム・技術・プロセスを共に整えます。

お問い合わせ