目次
はじめに
本記事で解説する内容
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.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つの文字列にまとめたものです。
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.User
users
は ユーザー情報の一覧を保持するための変数です。
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.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_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 r
r *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.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 "}]
が出力されたら成功です。
コメント