【Golang】Ginを活用したAPIの実装方法をサンプルコード付きで解説

目次

はじめに

本記事で解説する内容

DB内にデータを登録(POST)・取得(GET)するAPIの実装方法を、サンプルコード付きで解説します。

前提条件

  • PostgreSQLのインストールが完了していること
  • Golangのインストールが完了していること
参考記事

サンプルアプリのディレクトリ構成

api/
├── .env                # 環境変数(DB接続情報など)
├── go.mod              # Goモジュールの設定ファイル
├── go.sum              # 依存関係の管理ファイル
├── main.go             # エントリーポイント
│
├── config/             # 設定関連(DB接続)
│   ├── database.go     # DB接続処理
│
├── models/             # データモデル
│   ├── user.go         # Userモデルの定義
│
├── handlers/           # APIの処理(Controller相当)
│   ├── user_handler.go # ユーザー関連の処理
│
└── routes/             # ルーティング設定
    ├── user_routes.go  # ユーザー関連のルート

■ファイルの解説

ファイル説明
.envDB接続情報などの環境変数を格納
go.modGoモジュールの管理ファイル
go.sum
main.goエントリーポイント(アプリの起動処理)
database.goDB接続を管理
user.goUserモデルの定義
user_handler.goユーザー関連の処理
user_route.goユーザー関連のルート設定

①パッケージのインストール

サンプルアプリに必要な、外部パッケージのインストール方法を解説します。

go mod init api
go get github.com/gin-gonic/gin github.com/jmoiron/sqlx github.com/lib/pq github.com/joho/godotenv

■ソースコード解説

go mod init api

  • Goのモジュールを作成し、プロジェクトのルートディレクトリにgo.modというファイルを生成します。
  • go get ~
    • 外部パッケージをインストールします。
    • gin-gonic/gin : 軽量なWebフレームワーク
    • jmoiron/sqlx : database/sql を拡張し、扱いやすくしたDB操作ライブラリ
    • lib/pq : PostgreSQL用のドライバ
    • joho/godotenv.env ファイルを読み込むためのライブラリ

②テーブル作成

接続対象のデータベース・テーブルを、以下のように作成します。

  • データベース名:test_db
  • テーブル名:test_table
    • カラム1:user_id(Cahacter(10))
    • カラム2:user_name(Character(10))

上記データベース・テーブルの作成方法は、以下の記事で解説しています。

③DB接続情報の設定

③-1 .envファイル作成

DB接続情報を管理する.envを作成します。

■配置場所

api/
├── .env                # 環境変数(DB接続情報など)

■ソースコード

DB_USER=youruser
DB_PASSWORD=yourpassword
DB_NAME=test_db
DB_HOST=localhost
DB_PORT=5432
DB_SSLMODE=disable

■ソースコード解説

  • DB_USER=youruser:PostgreSQLのデータベース接続に使用するユーザー名
  • DB_PASSWORD=yourpasswordDB_USER に対応するパスワード
  • DB_NAME=test_db:接続するデータベースの名前
  • DB_HOST=localhost:データベースサーバーのホスト名(localhostはローカル環境を指します。)
  • DB_PORT=5432:PostgreSQLの接続ポート
  • SSL_MODE=disable:SSL接続の設定(disable にするとSSLを使わずに接続します。)

③-2 database.goファイル作成

DB接続処理を管理するdatabase.goファイルを作成します。

■配置場所

api/
├── config/             # 設定関連(DB接続)
│   ├── database.go     # DB接続処理

■ソースコード

package config

import (
	"fmt"
	"log"
	"os"

	"github.com/jmoiron/sqlx"
	"github.com/joho/godotenv"
	_ "github.com/lib/pq"
)

// グローバル変数定義
var DB *sqlx.DB

// データベース接続の初期化
func InitDB() {

	// .envファイルの読み込み
	err := godotenv.Load()
	if err != nil {
		log.Fatal(".envファイルの読みこみに失敗しました。", err)
	}

	// DSN作成
	dsn := fmt.Sprintf(
		"user=%s password=%s host=%s port=%s dbname=%s sslmode=%s",
		os.Getenv("DB_USER"),
		os.Getenv("DB_PASSWORD"),
		os.Getenv("DB_HOST"),
		os.Getenv("DB_PORT"),
		os.Getenv("DB_NAME"),
		os.Getenv("DB_SSLMODE"),
	)

	// DB接続
	DB, err = sqlx.Connect("postgres", dsn)
	if err != nil {
		log.Fatal("DB接続に失敗しました。", err)
	}
}

■処理フロー

STEP
グローバル変数定義
// グローバル変数定義
var DB *sqlx.DB
  • DB はグローバル変数として宣言
  • *sqlx.DB はポインタ型のデータベース接続オブジェクト
STEP
.env ファイルを読み込む
	// .envファイルの読み込み
	err := godotenv.Load()
	if err != nil {
		log.Fatal(".envファイルの読みこみに失敗しました。", err)
	}
  • .env ファイルを読み込み、環境変数をプログラム内で利用できるようにします。
  • .env が存在しない場合や読み込みに失敗した場合、err が発生します。
  • .env の読み込みに失敗した場合、プログラムを強制終了 (log.Fatal) します。
STEP
DB接続情報 (DSN: Data Source Name) を作成
	// DSN作成
	dsn := fmt.Sprintf(
		"user=%s password=%s host=%s port=%s dbname=%s sslmode=%s",
		os.Getenv("DB_USER"),
		os.Getenv("DB_PASSWORD"),
		os.Getenv("DB_HOST"),
		os.Getenv("DB_PORT"),
		os.Getenv("DB_NAME"),
		os.Getenv("DB_SSLMODE"),
	)
  • os.Getenv("DB_USER") などで .env に定義された環境変数を取得します。
  • fmt.Sprintf を使って、データベースの接続文字列 (DSN) を作成します。
DSNとは?
  • データベース接続情報を1つの文字列にまとめたものです。
  • sqlxdatabase/sql で データベースに接続するときに使用 されます。
STEP
DB接続
	// DB接続
	db, err = sqlx.Connect("postgres", dsn)
	if err != nil {
		log.Fatal("DB接続に失敗しました。", err)
	}
  • sqlx.Connect("postgres", dsn) を使って PostgreSQL に接続します。
  • DB というグローバル変数に接続オブジェクトを代入します。
  • データベースへの接続に失敗した場合、エラーメッセージを表示してプログラムを強制終了 (log.Fatal) します。

④データモデル定義

④-1 user.goファイルの作成

■配置場所

api/
├── models/             # データモデル
│   ├── user.go         # Userモデルの定義

■ソースコード

package models

type User struct {
	UserID   string `json:"user_id" db:"user_id"`
	UserName string `json:"user_name" db:"user_name"`
}

■処理フロー

STEP
構造体の定義
// User モデル
type User struct {
	UserID   string `json:"user_id" db:"user_id"`
	UserName string `json:"user_name" db:"user_name"`
}
  • この構造体は、データベースの test_table テーブルと対応するデータモデルで、APIでユーザー情報をやり取りする際に使用します。
  • タグ json:"user_id"
    • JSON 形式でデータを送受信するとき、フィールド名を "user_id" に変換します。
  • タグ db:"user_id"
    • データベースと連携する際、このフィールドが user_id カラム にマッピングされます。

⑤API処理の実装

⑤-1 user_handler.goの作成

■配置場所

api/
├── handlers/           # APIの処理(Controller相当)
│   ├── user_handler.go # ユーザー関連の処理

■ソースコード

package hand

import (
	"api/config"
	"api/models"
	"net/http"

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

// ユーザー一覧取得
func GetUsers(c *gin.Context) {
	var users []models.User
	err := config.DB.Select(&users, "SELECT * FROM users")
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, users)
}

// ユーザー登録
func CreateUser(c *gin.Context) {

	// リクエスト情報のバインド
	var user models.User
	if err := c.ShouldBindJSON(&user); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	// DB書き込み
	_, err := config.DB.Exec(`
		INSERT INTO test_table (user_id)
		VALUES
			($1, $2)
	`, user.UserID, user.UserName)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "User created successfully"})
}

■処理フロー

STEP
[ユーザー一覧取得関数] 関数定義
// ユーザー一覧取得
func GetUsers(c *gin.Context) {...}
  • CetUsers は Gin フレームワーク の Context を受け取る関数です。
  • c *gin.Context を通じて、HTTPリクエストのデータ取得やレスポンスの返却 を行います。
STEP
[ユーザー一覧取得関数] DB読み込み
	var users []models.User
	err := config.DB.Select(&users, "SELECT * FROM test_table")
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
    c.JSON(http.StatusOK, users)
  • var users []models.User
    • users は ユーザー情報の一覧を保持するための変数です。
  • err := config.DB.Select(&users, "SELECT * FROM test_table")
    • PostgreSQL から test_table 内のすべてのレコードを取得 し、結果を users スライスに格納します。
  • if err != nil { … }
    • もし err にエラーが格納されていた場合、データ取得に失敗しているため、クライアントに 500 Internal Server Error を返します。
    • その後 return により処理を中断し、以降のコードが実行されないようにしています。
  • c.JSON(http.StatusOK, users)
    • エラーがなければ、取得した users スライスを JSON 形式でクライアントに返します。
    • HTTP ステータスコード 「200 OK」 を設定し、JSON データをレスポンスとして送信します。
STEP
[ユーザー作成関数] 関数定義
// ユーザー登録
func CreateUser(c *gin.Context) {...}
  • CreateUser は Gin フレームワーク の Context を受け取る関数です。
  • c *gin.Context を通じて、HTTPリクエストのデータ取得やレスポンスの返却 を行います。
STEP
[ユーザー作成関数] HTTPリクエストのバインド
	var user models.User
	if err := c.ShouldBindJSON(&user); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
  • var user models.User
    • user に、クライアントから送られてきた JSON データをバインドしていきます。
  • if err := c.ShouldBindJSON(&user); err != nil { … }
    • c.ShouldBindJSON(&user) は Gin フレームワークのメソッド で、HTTP リクエストの ボディに含まれる JSON データを user 構造体にバインド します。
  • バインドが成功すると、user 変数にクライアントから送られてきた JSON のデータが格納されます。もしバインドに失敗した場合、エラー内容が err に設定されます。
STEP
[ユーザー作成関数] DB書き込み
	_, err := config.DB.Exec("INSERT INTO test_table (user_id, user_name) VALUES ($1, $2)", user.UserID, user.UserName)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
  • _, err := config.DB.Exec("INSERT INTO test_table (user_id, user_name) VALUES ($1, $2)", user.UserID, user.UserName)
    • config.DB.Exec は、Exec メソッドを使ってSQL クエリを実行するためのコードです。
    • このクエリでは、test_table というテーブルに user_iduser_name の2つのカラムに対してデータを挿入します。
  • if err != nil { … }
    • errnil でない場合、つまり SQL クエリ実行中にエラーが発生した場合 に次の処理が実行されます。
    • err != nil の条件式が エラーが発生したことを示します。
  • c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
    • c.JSON は、HTTP レスポンスをクライアントに返すためのメソッドです。
    • http.StatusInternalServerError は HTTP ステータスコード 500を意味し、サーバー内でエラーが発生したことを示します。
    • gin.H{"error": err.Error()} は、エラーメッセージを JSON 形式でレスポンスとして返すためのコードです。
STEP
[ユーザー作成関数] レスポンス返却
c.JSON(http.StatusCreated, gin.H{"message": "User created"})
  • c.JSON は、Gin フレームワークのメソッドで、HTTP レスポンスを JSON 形式で返すために使用します。
    • 第一引数:HTTP ステータスコードを指定します。
      • http.StatusCreated は定数で、HTTP ステータスコード 201 を意味します。
    • 第二引数:JSON 形式のレスポンスボディを指定します。
  • gin.H{"message": "User created"}
    • gin.H は Gin のヘルパーで、簡易的にマップ(key-value ペア)を作成するために使います。この場合、以下のように JSON オブジェクトを作成しています。
      • "message" は JSON オブジェクトのキー。
      • "User created" はそのキーに対応する値で、ユーザーが正常に作成されたことを伝えるメッセージです。

⑥ルーティングの実装

⑥-1 user_routes.goファイルの作成

APIリクエストにおけるルーティングの設定を行います。

■配置場所

api/
└── routes/             # ルーティング設定
    ├── user_routes.go  # ユーザー関連のルート

■ソースコード

package routes

import (
	"api/handlers"

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

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

	r.GET("/users", handlers.GetUsers)
	r.POST("/users", handlers.CreateUser)

	return r
}

■処理フロー

STEP
ルーティング設定
// ユーザー関連のルート
func SetupRouter() *gin.Engine {
	r := gin.Default()

	r.GET("/users", handlers.GetUsers)
	r.POST("/users", handlers.CreateUser)

	return r
  • r *gin.EngineGin フレームワークのエンジンオブジェクト(ルータ)を引数として受け取ります。
  • r.GET は、HTTP GET リクエストに対応するルートを定義します。
  • r.POST は、HTTP POST リクエストに対応するルートを定義します。

⑥-2 main.goファイルの作成

配置場所

api/
├── main.go             # エントリーポイント

■ソースコード

package main

import (
	"log"

	"api/config"
	"api/routes"
)

func main() {
	config.InitDB()
	defer config.DB.Close()

	r := routes.SetupRouter()
	log.Fatal(r.Run(":8080"))
}

■処理フロー

STEP
データベースの初期化
	config.InitDB()
  • アプリケーションの動作に必要なデータベース接続を確立するために、プログラム開始時にデータベース接続を初期化します。
  • config パッケージ内の InitDB 関数を呼び出して、データベースの接続を初期化しています。
STEP
データベース接続の終了
defer config.DB.Close()
  • defer キーワードを使って、main 関数が終了する際に config.DB.Close() が呼ばれるようにしています。
  • これにより、データベースの接続を適切に終了することができます。
STEP
ルーターの設定
r := routes.SetupRouter()
  • routes パッケージ内の SetupRouter 関数を呼び出して、HTTPリクエストに対するルーティングを設定した r を取得します。
  • この関数では、アプリケーションが処理するURLパスと対応するハンドラ関数を定義しています
STEP
Webサーバーの起動
log.Fatal(r.Run(":8080"))
  • r.Run(":8080") でWebサーバーをポート8080で開始します。
  • もしサーバーの起動に失敗した場合、log.Fatal が呼ばれ、そのエラーメッセージがログに記録され、プログラムが終了します。

動作確認

STEP
サーバー起動
go run main.go
STEP
POSTメソッドの実行(ユーザー登録)
curl -X POST "http://localhost:8080/users" -H "Content-Type: application/json" -d "{\"user_id\": \"123\", \"user_name\": \"tamura\"}"

 ⇒{"message":"User created successfully"}が出力されたら成功です。

STEP
GETメソッドの実行(ユーザー一覧取得)
curl -X GET "http://localhost:8080/users"

 ⇒[{"user_id":"123 ","user_name":"tamura "}]が出力されたら成功です。

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

コメント

コメントする

目次