2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ToDoアプリの作成(マイグレーション編)

Last updated at Posted at 2024-10-20

はじめに

Udemyの講座「Echo/Go + Reactで始めるモダンWebアプリケーション開発」を基にEcho/Goの部分だけにはなるのですが、勉強した内容をまとめていこうと思います。
長くなるので何回かに分けてブログを執筆しようと思っています。

プロジェクトの作成

まずはVSCodeにてフォルダ(GO-REST-API)を作成し,下記コマンドを実行し新しくGoのプロジェクトを作成します。

go mod init go-rest-api

ローカルでPostgreSQLを起動

ローカルでpostgresを起動するため、プロジェクト直下にdocker-compose.ymlファイルを作成します。
docker-compose.yml
version: "3.8"
services:
  dev-postgres:
    image: postgres:15.1-alpine
    ports:
      - 5434:5432
    environment:
      //PostgreSQLに必要なユーザー名
      POSTGRES_USER: udemy
      //PostgreSQLに必要なパスワード
      POSTGRES_PASSWORD: udemy
      //PostgreSQLに必要なDB名
      POSTGRES_DB: udemy
    restart: always
    networks:
      - lesson
networks:
  lesson:

上記のdocker-compose.ymlを作成したら、docker compose up -dでコンテナを立ち上げていきます。
※念の為docker psでpostgres:15.1-alpineのコンテナが起動しているかを確認しておく。

環境変数の設定

下記のファイルを作成して、アプリケーションに使用する環境変数の設定を行います。
.env
PORT=8080
//PostgreSQLに必要なユーザー名
POSTGRES_USER=udemy
//PostgreSQLに必要なパスワード
POSTGRES_PW=udemy
//PostgreSQLに必要なDB名
POSTGRES_DB=udemy
//PostgreSQLのポート番号
POSTGRES_PORT=5434
//PostgreSQLのホスト名
POSTGRES_HOST=localhost
//JWTを生成するためのシークレットキー(任意の値)
SECRET=uu5pveql
//開発ノード
GO_ENV=dev
API_DOMAIN=localhost
//フロントエンドのパス
FE_URL=http://localhost:3000

ユーザーのモデル構造作成

下記のコードは、GORMライブラリを使って、データベースにユーザー情報を保存し、APIレスポンスを生成する際に使用されます。
下記のコードは、ユーザーを表すデータ構造 (User) と、APIレスポンスとして使用するデータ構造 (UserResponse) を定義しています。
User 構造体は、ユーザーのID、メールアドレス、パスワード、作成日時、更新日時を格納します。
UserResponse 構造体は、APIレスポンスとして、ユーザーのIDとメールアドレスをクライアントに返します。
model/user.go
package model

import "time"

type User struct {
    //構造体のオブジェクトをJSONに変換したときに自動的に小文字に変更
	ID        uint      `json:id gorm:"primaryKey"`
	Email     string    `json:"email" gorm:"unique"`
	Password  string    `json:"password"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
}

type UserResponse struct {
	ID    uint   `json:id gorm:"primaryKey"`
	Email string `json:"email" gorm:"unique"`
}

json:とすると、構造体のオブジェクトをJSONに変換したときに自動的にフィールド名を小文字に変更してくれる。
また、gorm:"primaryKeyはオブジェクトの主キーとして認識する。
gorm:"uniqueは重複を許さないユニークなフィールドという制約をつけることが出来る。

6.タスクのモデル構造作成
下記のコードは、Go言語でREST APIアプリケーションで使用されるタスクのデータ構造(モデル)を定義しています。
下記のコードは、タスクを表すデータ構造 (Task) と、APIレスポンスとして使用するデータ構造 (TaskResponse) を定義しています。
Task 構造体は、タスクのID、タイトル、作成日時、更新日時、関連するユーザーの情報を格納します。
TaskResponse 構造体は、APIレスポンスとして、タスクのID、タイトル、作成日時、更新日時をクライアントに返します。

model/task.go
package model

import "time"

type Task struct {
	ID        uint      `json:"id" gorm:"primaryKey"`
	Title     string    `json:"title" gorm:"not null"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
	User      User      `json: "user" gorm:"foreignKey:UserId: constraint:OnDelete:CASCADE"`
	UserId    uint      `json:"user_id" gorm:"not null"`
}

type TaskResponse struct {
	ID        uint      `json:id gorm: "primaryKey"`
	Title     string    `json: "title" gorm: "not null"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
}

gorm:"foreignKey:UserId:はユーザーモデルの主キーであるIDの値がタスクモデルのUserIdに格納されます。
1対多のリレーションを張ることが出来る。(複数のテーブルと関連付けることが出来る)

gorm: "not null"空の値を許可しない。

constraint:OnDelete:CASCADEはユーザーを削除した際、削除したユーザーのタスクを自動的に削除します。

DBへの接続

下記のコードは、Go言語でデータベースへの接続を作成し、その接続を管理する関数を提供する db パッケージです。
下記のコードは、NewDB() 関数を使って、PostgreSQLデータベースへの接続を作成します。
環境変数 GO_ENV が "dev" に設定されている場合は、.env ファイルから環境変数をロードします。
データベース接続が成功すると、"Connected" を出力して、データベース接続オブジェクトを返します。
CloseDB() 関数は、データベース接続オブジェクトを引数に受け取って、データベース接続を閉じます。
db/db.go
package db

import (
	"fmt"
	"log"
	"os"

	"github.com/joho/godotenv"
	"gorm.io/driver/postgres"
	"gorm.io/gorm"
)

func NewDB() *gorm.DB {
    //環境変数 `GO_ENV` が "dev" に設定されている場合は、`godotenv.Load()` を使って `.env` ファイルから環境変数をロードします。
	if os.Getenv("GO_ENV") == "dev" {
		err := godotenv.Load()
		if err != nil {
			log.Fatalln(err)
		}
	}
    //環境変数からPostgreSQLの接続URLを作成します。
	url := fmt.Sprintf("postgres://%s:%s@%s:%s/%s", os.Getenv("POSTGRES_USER"),
		os.Getenv("POSTGRES_PW"), os.Getenv("POSTGRES_HOST"),
		os.Getenv("POSTGRES_PORT"), os.Getenv("POSTGRES_DB"))
    //PostgreSQLドライバーを使って、データベースに接続します。
	db, err := gorm.Open(postgres.Open(url), &gorm.Config{})
    //エラーが発生した場合、ログにエラーメッセージを出力してプログラムを終了します。
	if err != nil {
		log.Fatalln(err)
	}
    //接続が成功した場合、"Connected" を出力します。
	fmt.Println("Connected")
    //データベース接続オブジェクトを返します。
	return db
}

func CloseDB(db *gorm.DB) {
    //GORMデータベース接続から、SQLデータベース接続オブジェクトを取得します。
	sqlDB, _ := db.DB()
    //SQLデータベース接続を閉じます。エラーが発生した場合、ログにエラーメッセージを出力してプログラムを終了します。
	if err := sqlDB.Close(); err != nil {
		log.Fatalln(err)
	}
}

※外部パッケージを使用するのでgo mod tidyコマンドを実行してインストールします。

マイグレーション

下記のコードは、REST APIアプリケーションの初期設定として、データベースへの接続を作成し、データベーススキーマを自動的にマイグレートします。
ここでのポイントは、AutoMigrate 関数を使い、User 構造体と Task 構造体のスキーマをデータベースに自動的に作成します。
migrate/migrate.go
package main

import (
	"fmt"
	"go-rest-api/db"
	"go-rest-api/model"
)

func main() {
    //`db` パッケージの `NewDB()` 関数を呼び出して、データベースへの接続を作成し、接続オブジェクト `dbConn` に格納します。
	dbConn := db.NewDB()
    //`defer` キーワードを使って、`main` 関数の最後(プログラムの終了前)に "Successfully Migrated" を出力する処理を登録します。
	defer fmt.Println("Successfully Migrated")
    //`defer` キーワードを使って、`main` 関数の最後(プログラムの終了前)に `db` パッケージの `CloseDB()` 関数を呼び出して、データベース接続を閉じる処理を登録します。
	defer db.CloseDB(dbConn)
    //`dbConn.AutoMigrate(&model.User{}, &model.Task{})`:  `dbConn` オブジェクトを使って、`User` 構造体と `Task` 構造体のスキーマをデータベースに自動的にマイグレートします。
	dbConn.AutoMigrate(&model.User{}, &model.Task{})
}

下記コマンドでマイグレーションを実行します。
GO_ENV=dev go run migrate/migrate.go

成功すると下記のメッセージが出てきます。

Connected
Successfully Migrated

データベースにテーブルが生成されているか確認

pgAdminにて確認していきます。 初めて起動する場合は、好きなパスワードを設定してください。 下記画像のAdd New Serverをクリックします。

スクリーンショット 2024-10-18 22.16.11.png

下記画像のNameを設定を行います。(好きな名前で大丈夫です)
スクリーンショット 2024-10-17 17.42.07.png

Connectionタブに移動して.envで設定している環境変数を入力。
スクリーンショット 2024-10-18 21.22.57.png

tasksテーブルにtask.goで定義したフィールドが反映されているか確認。
スクリーンショット 2024-10-18 21.24.37.png
tasksテーブルにtask.goで定義したフィールドが反映されています。
スクリーンショット 2024-10-18 21.31.09.png

今度はusersテーブルにuser.goで定義したフィールドが反映されているか確認。
スクリーンショット 2024-10-18 21.33.34.png
usersテーブルにuser.goで定義したフィールドが反映されています。
スクリーンショット 2024-10-18 21.34.16.png

まとめ

今回はマイグレーションのやり方についてまとめました。
次回はユーザーの新規追加、ログイン、ログアウト機能を実装していきます。
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?