🐒

【Go】GinでCRUDなREST API作ってみた #1 (環境設定とモデルのマイグレーションまで)

2024/09/15に公開

Itemオブジェクトの作成(Create)、読み込み(Read)、更新(Update)、削除(Delete)を行うAPIをginフレームワーク、postgresqlを使用して作りました。
さらに、pgAdmin(postgresql用のGUI管理ツール)を使用し、データベースサーバーを作成しました。

はじめに

Ginフレームワークの特徴

  • 軽量で高速なパフォーマンス
    • 基数木(redix tree)を元にしたルーティング、小さなメモリフットプリント、リフレクションなし、予測可能な API 性能などの特徴があります。
  • ミドルウェアのサポート
    • 受信したHTTPリクエストをミドルウェアのチェーンと最終的なアクションによりハンドリングできます。たとえば、ロガー、認証、GZIP、さらに DB へのメッセージのポストなどが可能です。
  • クラッシュフリー
    • HTTPリクエスト中に発生したパニcをキャッチし、回復することが可能で、サーバーが常に利 用可能な状態になる

などなどGinは素晴らしい特徴を兼ね備えています。

使用するライブラリ紹介

  1. godotenv
    goプロジェクトで.envを使用して環境変数を管理するためのライブラリ。
    今回はデータベースサーバーの環境変数などを.envファイルで管理します。

https://github.com/joho/godotenv
2. gorm
golangのORM(Object Relational mapping)ライブラリ。
特徴は、アソシエーション機能、イベントフック、トランザクションなどが提供されています。

https://gorm.io/ja_JP/docs/index.html

プロジェクトの構造

.
├── controllers
│   └── item_controller.go
├── docker-compose.yaml
├── dto
│   └── item_dto.go
├── go.mod
├── go.sum
├── infra
│   ├── db.go
│   └── initializer.go
├── main.go
├── migrations
│   └── migration.go
├── models
│   └── item.go
├── repositories
│   └── item_repository.go
└── services
    └── item_service.go
  • 3層アーキテクチャ
    • Controller
      • リクエストデータのハンドリングやレスポンスの設定
    • Service
      • 実現したい機能(ビジネスロジック)の実装
    • Repository
      • データの永続化やデータソースとのやりとり

プロジェクトの作成

  1. go.modファイルを以下のコマンドで作成する
sh
$ go mod init <プロジェクト名>

go.modファイルは使用されるモジュールの依存関係を管理するファイルです

  1. ginのインストール
sh
$ go get -u github.com/gin-gonic/gin
  1. main.goをプロジェクトのルートに作成

データベース環境の構築

  1. docker-compose.yamlを使って、データベース環境の構築
docker-compose.yaml
version: "3.8"
services:
  postgres:
    image: postgres:16-alpine
    container_name: postgres
    ports:
      - 5433:5432
    volumes:
      - ./docker/postgres/init.d:/docker-entrypoint-initdb.d
      - ./docker/postgres/pgdata:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: ginuser
      POSTGRES_PASSWORD: ginpassword
      POSTGRES_INITDB_ARGS: "--encoding=UTF-8"
      POSTGRES_DB: fleamarket
    hostname: postgres
    restart: always
    user: root

  pgadmin:
    image: dpage/pgadmin4
    restart: always
    ports:
      - 81:80
    environment:
      PGADMIN_DEFAULT_EMAIL: gin@example.com
      PGADMIN_DEFAULT_PASSWORD: ginpassword
    volumes:
      - ./docker/pgadmin:/var/lib/pgadmin
    depends_on:
      - postgres
  1. docker-composeを起動
sh
$ docker compose up -d
  1. pgAdmin 4にログイン

    docker-compose.yamlで指定したポート番号(上記の記述だと81番ポート)を指定してブラウザでログイン画面に行きます。docker-compose.yamlで指定したemailアドレスとパスワードでログイン。
  2. データベースサーバーの作成

    ログイン後このような画面に遷移するかと思います。
    この画面の「新しいサーバーを追加」をクリックし、新しいサーバーの登録を行なっていきます


    docker-compose.yaml通りに設定し終えたら、保存ボタンを押します。

    しっかり、作成したデータベースサーバーが登録されています。

データベースとの接続設定

  1. gorm,sqlite用のドライバー、postgressql用のドライバーのインストール
sh
$ go get -u gorm.io/gorm
$ go get -u gorm.io/driver/sqlite
$ go get -u gorm.io/driver/postgres
  1. godotenvパッケージのインストール
sh
$ go get github.com/joho/godotenv
  1. .envファイルの作成
.env
DB_HOST=localhost
DB_USER=ginuser
DB_PASSWORD=ginpassword
DB_NAME=fleamarket
DB_PORT=5433
  1. initializer.goで.envファイルのロード機能を記述
infra
package infra

import (
	"log"

	"github.com/joho/godotenv"
)

func Initialize() {
	err := godotenv.Load()
	if err != nil {
		log.Fatal("Error loading .env file")
	}
}

  1. db.goにデータベースのセットアップを記述
/infra/db.go
package infra

import (
	"fmt"
	"log"
	"os"

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

func SetupDB() *gorm.DB {
	dsn := fmt.Sprintf(
		"host=%s user=%s password=%s dbname=%s port=%s sslmode=disable TimeZone=Asia/Tokyo",
		os.Getenv("DB_HOST"),
		os.Getenv("DB_USER"),
		os.Getenv("DB_PASSWORD"),
		os.Getenv("DB_NAME"),
		os.Getenv("DB_PORT"),
	)

	db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
	if err != nil {
		panic("Failed to connect database")
	}

	log.Println("Database connection successful!") 

	return db
}

モデルの作成

item.goにItem構造体(CRUD操作の対象モデル)を記述

/models/item.go
package models

import "gorm.io/gorm"

type Item struct {
	gorm.Model
	Name        string `gorm:"not null"`
	Price       uint   `gorm:"not null"`
	Description string
	SoldOut     bool `gorm:"not null;default:false"`
}


gorm.ModelにはID、CreatedAt、UpdatedAt、DeletedAt属性が含まれている。

マイグレーション

  1. migration.goファイルを作成
/migrations/migration.go
package main

import (
	"<プロジェクト名>/infra"
	"<プロジェクト名>/models"
)

func main() {
    infra.Initialize()
	db := infra.SetupDB()

	if err := db.AutoMigrate(&models.Item{}); err != nil {
		panic("Failed to migrate database")
	}
}
  1. コマンドでマイグレーションの実行
sh
$ go run migrations/migration.go

終わりに

次回からAPI構築の記事を書いていきたいと思います

参考

今回はYu Shinozakiさんの「Gin入門 Go言語ではじめるサーバーサイド開発」というUdemyの講義を見ながら作成いたしました。とてもわかりやすくておすすめです!
https://www.udemy.com/course/gin-golang/?couponCode=KEEPLEARNING
ginフレームワークの公式ドキュメント
https://gin-gonic.com/ja/

Discussion