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

前提条件
- PostgreSQLのインストールが完了していること
- Golangのインストールが完了していること
参考記事
KONISHI Tech Note


PostgreSQLの環境構築|pgAminでのDB・テーブル・ユーザー作成・データ登録(INSERT)方法 | KONISHI Tech …
本記事の内容 PostgreSQLを初めて扱う人が、インストールからpgAdminを活用した基本操作が行えるように、下記内容を解説します。 この記事で分かること PostgreSQLのインス…
KONISHI Tech Note


Go言語(Golang)の環境構築|サンプルアプリの実行までを解説 | KONISHI Tech Note
はじめに 以下ステップで環境構築・サンプルアプリの実行までを行います。 本記事の流れ Goのインストール Goプロジェクトの作成 サンプルアプリの作成 サンプルアプリの実…
サンプルアプリのディレクトリ構成
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 # ユーザー関連のルート
■ファイルの解説
| ファイル | 説明 |
|---|---|
| .env | DB接続情報などの環境変数を格納 |
| go.mod | Goモジュールの管理ファイル |
| go.sum | |
| main.go | エントリーポイント(アプリの起動処理) |
| database.go | DB接続を管理 |
| user.go | Userモデルの定義 |
| 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))
上記データベース・テーブルの作成方法は、以下の記事で解説しています。
KONISHI Tech Note


PostgreSQLの環境構築|pgAminでのDB・テーブル・ユーザー作成・データ登録(INSERT)方法 | KONISHI Tech …
本記事の内容 PostgreSQLを初めて扱う人が、インストールからpgAdminを活用した基本操作が行えるように、下記内容を解説します。 この記事で分かること PostgreSQLのインス…
③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=yourpassword:DB_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.DBDBはグローバル変数として宣言*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つの文字列にまとめたものです。
sqlxやdatabase/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"に変換します。
- JSON 形式でデータを送受信するとき、フィールド名を
- タグ
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.Userusersは ユーザー情報の一覧を保持するための変数です。
err := config.DB.Select(&users, "SELECT * FROM test_table")- PostgreSQL から
test_table内のすべてのレコードを取得 し、結果をusersスライスに格納します。
- PostgreSQL から
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.Useruserに、クライアントから送られてきた 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_idとuser_nameの2つのカラムに対してデータを挿入します。
if err != nil { … }errがnilでない場合、つまり 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 形式のレスポンスボディを指定します。
- 第一引数:HTTP ステータスコードを指定します。
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 rr *gin.EngineはGinフレームワークのエンジンオブジェクト(ルータ)を引数として受け取ります。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.goSTEP
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 "}]が出力されたら成功です。

コメント