Go言語: フレームワークなしからGinとGORMへの移行ガイド

# はじめに

ソフトウェア開発における効率と品質の向上は、技術選択によって大きく左右されます。特に、Go 言語を用いた開発においては、フレームワークや ORM（オブジェクトリレーショナルマッピング）の導入が、その鍵を握ることが多いです。本記事では、Go 言語での開発プロセスを、フレームワーク「Gin」と ORM「GORM」を導入することでどのように変化させることができるかを詳細に解説します。加えて、機能改善に関する変更点も取り上げます。

https://github.com/tonbiattack/go-task-management-api

従来、フレームワークや ORM を使用しない「素の Go」での開発は、柔軟性と軽量さを持ち合わせていますが、大規模なプロジェクトや複雑なデータハンドリングを伴う場合、コードの管理や拡張性の面で課題を抱えることがあります。Gin と GORM の導入は、これらの課題に対して効果的な解決策を提供し、開発の生産性を向上させる可能性があります。

本記事では、Gin と GORM を用いることのメリットと、それを実現するための具体的なステップ、さらに移行プロセス中に考慮すべきポイントについて、実例を交えながら解説します。Go 言語でのより効率的かつ強力なアプリケーション開発を目指す開発者にとって、この記事が有益なガイドとなることを願っています。

サンプルアプリの題材はタスク管理アプリです。

---

## テーブル構造

このテーブルは、タスクの基本的な情報を格納するために使用されます。テーブルの各カラムは以下の通りです：

- `id` (char(36)): タスクの一意識別子（UUID 形式）。
- `title` (varchar(255)): タスクのタイトル。
- `description` (text): タスクの詳細説明。
- `status` (varchar(50)): タスクの状態。デフォルトは「PENDING」(未完了)。
- `created_at` (datetime): タスクの作成日時。
- `updated_at` (datetime): タスクの最終更新日時。
- `deadline` (datetime): タスクの期限日。

# 目次

1. [dbconfig.go](#dbconfiggo) - データベース設定の管理
2. [task.go](#taskgo) - タスクモデルの定義
3. [task_repository.go](#task_repositorygo) - データベースとのやり取りを担当するリポジトリ層
4. [task_handler.go](#task_handlergo) - HTTP リクエストの処理とレスポンスの生成
5. [main.go](#maingo) - アプリケーションのエントリポイント

## dbconfig.go

`dbconfig.go` は、Go 言語で開発されたアプリケーションにおいて、データベースの設定を管理するための重要なファイルです。このファイルでは、データベース接続に必要な情報（ホスト名、ポート、ユーザー名、パスワード、データベース名など）を定義し、アプリケーションがデータベースに接続する際に使用します。通常、このファイルにはデータベース接続を確立するための関数が含まれており、データベースへの接続設定の一元化に寄与します。dbconfig.go の導入によって、アプリケーション全体でのデータベース接続の設定が統一され、開発やメンテナンスが容易になります。これにより、開発者はデータベース接続の詳細について個別に気を配る必要がなくなり、よりアプリケーションのビジネスロジックに集中することが可能になります。

# dbconfig.go の変更点

## 1. データベース接続のアプローチの変更

### 以前のコード

以前のコードでは、標準の`database/sql`パッケージを使用して MySQL データベースに接続していました。

### 新しいコード

新しいコードでは、`gorm.io/gorm`を利用してデータベース接続を行います。GORM は Go 言語の強力な ORM ライブラリで、開発の効率性と安全性を高めます。

## 2. 構造体の導入

新しいコードでは、`DBConfig`という名の構造体を導入しています。この構造体はデータベース接続の設定を保持し、コードの可読性と保守性を向上させます。

## 3. データベース接続の初期化関数

新しいコードでは、`InitDB`関数を使用してデータベース接続を初期化します。この関数は`gorm.DB`オブジェクトを返し、GORM の機能を活用することができます。

## 4. DSN（Data Source Name）の形式の変更

DSN の形式が更新され、新しいパラメータが追加されています。これにより、データベース接続時の文字コードや時刻の取り扱いが改善されます。

## 5. エラーハンドリングの強化

データベース接続時のエラーハンドリングが強化されました。接続に失敗した場合、アプリケーションはエラーをログに記録し、実行を停止します。

これらの変更により、`dbconfig.go`はより堅牢でメンテナンスしやすいコードになりました。また、GORM の導入により、データベース操作の効率性が大幅に向上しました。

## 変更前後のコード比較

```diff
diff --git a/pkg/config/dbconfig.go b/pkg/config/dbconfig.go
index d3a320e..af5b983 100644
--- a/pkg/config/dbconfig.go
+++ b/pkg/config/dbconfig.go
@@ -1,42 +1,42 @@
 package config

 import (
-	"database/sql"
 	"fmt"
 	"log"

-	_ "github.com/go-sql-driver/mysql"
+	"gorm.io/driver/mysql"
+	"gorm.io/gorm"
 )

-// DB はアプリケーション全体で使用されるグローバルなデータベース接続です。
-var DB *sql.DB
-
-func init() {
-	var err error
-
-	dbUser := "root"
-	dbPassword := ""
-	dbHost := "127.0.0.1"
-	dbPort := "3306"
-	dbName := "task_management"
-
-	// データソース名を作成します
-	dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?parseTime=true", dbUser, dbPassword, dbHost, dbPort, dbName)
+// DBConfig はデータベース接続の設定情報を保持します
+type DBConfig struct {
+	Host     string
+	Port     string
+	User     string
+	Password string
+	Name     string
+}

-	// データベース接続を開きます
-	DB, err = sql.Open("mysql", dsn)
-	if err != nil {
-		log.Fatalf("データベースを開く際のエラー: %v", err)
+// InitDB は新しいデータベース接続を初期化して返します
+func InitDB() *gorm.DB {
+	config := DBConfig{
+		Host:     "127.0.0.1",
+		Port:     "3306",
+		User:     "root",
+		Password: "",
+		Name:     "task_management",
 	}

-	// データベース接続をチェックします
-	err = DB.Ping()
+	// DSN（Data Source Name）を作成
+	dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
+		config.User, config.Password, config.Host, config.Port, config.Name)
+
+	// GORMを使ってデータベースに接続
+	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
 	if err != nil {
-		log.Fatalf("データベースのping時のエラー: %v", err)
+		log.Fatalf("データベース接続に失敗しました: %v", err)
 	}
-}

-// GetDB はデータベース接続を返します
-func GetDB() *sql.DB {
-	return DB
+	// 接続を返す
+	return db
 }
```

## task.go

`task.go`は、データベースのテーブル構造を表すモデルクラスの一例です。Go 言語のアプリケーション開発において、モデルクラスはデータベース内のテーブルと直接対応し、テーブルの各カラムをクラスのフィールドとして表現します。このクラスは、アプリケーションがデータベースのデータを操作する際の基礎となり、データの取得、挿入、更新などの処理に使用されます。モデルクラスの定義により、アプリケーションはデータベースの構造を反映した形でデータを扱うことが可能になり、開発者はデータベースの操作を直感的かつ効率的に行うことができます。このように、モデルクラスはデータベースとアプリケーションの間の橋渡し役として重要な役割を果たします。

# task.go の変更点

## Status フィールドの変更

`Status`フィールドが`*string`（文字列のポインタ）型に変更され、GORM の`default`タグが追加されました。これにより、`Status`が空の場合にデフォルト値として`'pending'`が自動的に設定されます。

## Deadline フィールドの追加

新たに`Deadline`フィールドが追加され、これは`*time.Time`（時刻のポインタ）型を使用しています。このフィールドはタスクの期限日を表し、オプショナルなフィールドとして定義されています。

これらの変更により、タスクモデルはより柔軟なデータハンドリングを可能にし、GORM を使ったデータベース操作の効率化に貢献します。

## 変更前後のコード比較

```diff
diff --git a/pkg/model/task.go b/pkg/model/task.go
index a05416d..d4ad0b3 100644
--- a/pkg/model/task.go
+++ b/pkg/model/task.go
@@ -6,10 +6,11 @@ import (

 // Task - タスクを表す構造体
 type Task struct {
-	ID          string    `json:"id"`
-	Title       string    `json:"title"`
-	Description string    `json:"description"`
-	Status      string    `json:"status"`
-	CreatedAt   time.Time `json:"created_at"`
-	UpdatedAt   time.Time `json:"updated_at"`
+	ID          string     `json:"id"`
+	Title       string     `json:"title"`
+	Description string     `json:"description"`
+	Status      *string    `json:"status" gorm:"default:'pending'"`
+	CreatedAt   time.Time  `json:"created_at"`
+	UpdatedAt   time.Time  `json:"updated_at"`
+	Deadline    *time.Time `json:"deadline"`
 }
```

## task_repository.go

`task_repository.go`は Go 言語でのアプリケーション開発におけるリポジトリパターンの実装例です。リポジトリクラスは、データモデル（この場合はタスク）とデータベースや他のデータストレージとの間のやり取りを担当します。このクラスはアプリケーションのビジネスロジックや HTTP リクエストハンドリングからデータアクセスロジックを分離し、データの取得、更新、削除などの操作を抽象化します。その結果、他のアプリケーションのコンポーネントは、データベースの詳細や複雑なクエリ構文を意識せずにデータ操作ができるようになります。このように、リポジトリパターンはアプリケーションのメンテナンス性と再利用性を高めるために重要な役割を果たします。

# task_repository.go の変更点

## データベース接続の変更

`sql.DB` から `gorm.DB` への変更により、データベース操作が GORM ORM を介して行われるようになりました。

## CRUD 操作の更新

以前は生の SQL クエリを使用してタスクの CRUD 操作を実行していましたが、新しいコードでは GORM のメソッドを使ってこれらの操作をより効率的に行っています。

- `CreateTask`
- `GetTaskByID`
- `GetAllTasks`
- `UpdateTask`
- `DeleteTask`

これらのメソッドが GORM の操作に更新されました。

## エラーハンドリングの改善

GORM のエラーハンドリング機能を活用することで、より堅牢で読みやすいコードになりました。

これらの変更により、`task_repository.go`はより効率的かつメンテナンスしやすいコードになり、GORM の強力な機能を活用してデータベース操作を行うことが可能になりました。

## 変更前後のコード比較

```diff
diff --git a/pkg/repository/task_repository.go b/pkg/repository/task_repository.go
index 5002f7d..65d1e21 100644
--- a/pkg/repository/task_repository.go
+++ b/pkg/repository/task_repository.go
@@ -1,115 +1,46 @@
 package repository

 import (
-	"database/sql"
-
 	"github.com/tonbiattack/go-task-management-api/pkg/model"
+	"gorm.io/gorm"
 )

-// TaskRepository はタスクストレージへのアクセスを提供します。
 type TaskRepository struct {
-	DB *sql.DB
+	DB *gorm.DB
 }

-// NewTaskRepository は新しいTaskRepositoryを与えられたデータベース接続で作成します。
-func NewTaskRepository(db *sql.DB) *TaskRepository {
+func NewTaskRepository(db *gorm.DB) *TaskRepository {
 	return &TaskRepository{DB: db}
 }

 // CreateTask は新しいタスクをデータベースに挿入します。
-// タスクステータスが設定されていない場合、空の状態で省略されることを意味します。
 func (r *TaskRepository) CreateTask(task *model.Task) error {
-	var query string
-	var err error
-
-	if task.Status == "" {
-		// ステータスを省略
-		query = `INSERT INTO Task (id, title, description) VALUES (?, ?, ?)`
-		_, err = r.DB.Exec(query, task.ID, task.Title, task.Description)
-	} else {
-		// ステータスを含める
-		query = `INSERT INTO Task (id, title, description, status) VALUES (?, ?, ?, ?)`
-		_, err = r.DB.Exec(query, task.ID, task.Title, task.Description, task.Status)
-	}
-	return err
+	return r.DB.Create(task).Error
 }

 // GetTaskByID はIDによってタスクをデータベースから取得します。
 // 指定されたIDのタスクが存在しない場合、エラーを返します。
 func (r *TaskRepository) GetTaskByID(id string) (*model.Task, error) {
 	var task model.Task
-	query := `SELECT id, title, description, status, created_at, updated_at FROM Task WHERE id = ?`
-	err := r.DB.QueryRow(query, id).Scan(&task.ID, &task.Title, &task.Description, &task.Status, &task.CreatedAt, &task.UpdatedAt)
-	if err != nil {
-		return nil, err
-	}
-	return &task, nil
+	err := r.DB.First(&task, "id = ?", id).Error
+	return &task, err
 }

 // GetAllTasks はデータベース内のすべてのタスクを取得します。
 func (r *TaskRepository) GetAllTasks() ([]*model.Task, error) {
-	tasks := []*model.Task{}
-
-	query := `SELECT id, title, description, status, created_at, updated_at FROM Task`
-	rows, err := r.DB.Query(query)
-	if err != nil {
-		return nil, err
-	}
-	defer rows.Close()
-
-	for rows.Next() {
-		var task model.Task
-		if err := rows.Scan(&task.ID, &task.Title, &task.Description, &task.Status, &task.CreatedAt, &task.UpdatedAt); err != nil {
-			return nil, err
-		}
-		tasks = append(tasks, &task)
-	}
-
-	if err := rows.Err(); err != nil {
-		return nil, err
-	}
-
-	return tasks, nil
+	var tasks []*model.Task
+	err := r.DB.Find(&tasks).Error
+	return tasks, err
 }

 // UpdateTask は指定されたIDのタスクを更新します。
 // タスクが存在しない場合、エラーを返します。
 func (r *TaskRepository) UpdateTask(task *model.Task) error {
-	query := `UPDATE Task SET title = ?, description = ?, status = ?, updated_at = NOW() WHERE id = ?`
-	res, err := r.DB.Exec(query, task.Title, task.Description, task.Status, task.ID)
-	if err != nil {
-		return err
-	}
-
-	// 更新された行の数を確認
-	rowsAffected, err := res.RowsAffected()
-	if err != nil {
-		return err
-	}
-	if rowsAffected == 0 {
-		return sql.ErrNoRows
-	}
-
-	return nil
+	return r.DB.Save(task).Error
 }

 // DeleteTask は指定されたIDのタスクをデータベースから削除します。
 // タスクが存在しない場合、エラーを返します。
 func (r *TaskRepository) DeleteTask(id string) error {
-	query := `DELETE FROM Task WHERE id = ?`
-	res, err := r.DB.Exec(query, id)
-	if err != nil {
-		return err
-	}
-
-	// 削除された行の数を確認
-	rowsAffected, err := res.RowsAffected()
-	if err != nil {
-		return err
-	}
-	if rowsAffected == 0 {
-		return sql.ErrNoRows
-	}
-
-	return nil
+	return r.DB.Delete(&model.Task{}, id).Error
 }

```

## task_handler.go

`task_handler.go`は Go 言語の Web アプリケーションにおける HTTP リクエストハンドラーの役割を果たします。このクラスは、Web サーバーが受け取るさまざまな HTTP リクエスト（例えば GET, POST, PUT, DELETE）を処理し、それに対応する適切なレスポンスを生成する責任を持ちます。具体的には、ユーザーからのリクエストを受け取り、リクエストの内容に基づいて必要な処理（データベースの操作、ビジネスロジックの実行など）を行い、最終的にレスポンスをクライアントに返す流れを実装します。また、task_handler.go はリポジトリ層と連携し、データベースや他のストレージシステムとのやり取りを行います。これにより、アプリケーションのロジックとデータアクセスの層が分離され、コードの整理とメンテナンスのしやすさが向上します。

# task_handler.go の変更点

## フレームワークの変更

以前は`gorilla/mux`を使用して HTTP リクエストのルーティングとハンドリングを行っていましたが、新しいコードでは`gin-gonic/gin`フレームワークを採用しています。

## リクエスト処理の更新

新しいコードでは Gin のバインディング機能を使用してリクエストボディから JSON データを解析し、レスポンスの生成も Gin のメソッドを利用しています。

## ハンドラー関数のシンプル化

新しいコードでは、ハンドラー関数がよりシンプルで読みやすくなり、エラー処理も Gin のヘルパーメソッドを使って簡潔に行われています。

これらの変更により、`task_handler.go`はより効率的かつシンプルなコードになり、Gin フレームワークの強力な機能を活用してタスク関連の HTTP リクエストの処理を行うことが可能になりました。

## 変更前後のコード比較

```diff
diff --git a/pkg/handler/task_handler.go b/pkg/handler/task_handler.go
index d8b57d9..8eeb4b2 100644
--- a/pkg/handler/task_handler.go
+++ b/pkg/handler/task_handler.go
@@ -1,132 +1,103 @@
 package handler

 import (
-	"encoding/json"
 	"net/http"

+	"github.com/gin-gonic/gin"
 	"github.com/google/uuid"
-	"github.com/gorilla/mux"
 	"github.com/tonbiattack/go-task-management-api/pkg/model"
 	"github.com/tonbiattack/go-task-management-api/pkg/repository"
 )

-// TaskHandler - タスク関連のHTTPハンドラーを保持する構造体です。
 type TaskHandler struct {
 	Repo *repository.TaskRepository
 }

-// NewTaskHandler - 新しいTaskHandlerを作成します。
 func NewTaskHandler(repo *repository.TaskRepository) *TaskHandler {
 	return &TaskHandler{Repo: repo}
 }

 // CreateTask - POST /tasks に対するハンドラー関数です。
-func (h *TaskHandler) CreateTask(w http.ResponseWriter, r *http.Request) {
+func (h *TaskHandler) CreateTask(c *gin.Context) {
 	var task model.Task
-	if err := json.NewDecoder(r.Body).Decode(&task); err != nil {
-		http.Error(w, "Invalid request body", http.StatusBadRequest)
+	if err := c.BindJSON(&task); err != nil {
+		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})
 		return
 	}

-	// UUID生成
 	task.ID = uuid.New().String()

-	// データベースにタスクを保存
 	if err := h.Repo.CreateTask(&task); err != nil {
-		http.Error(w, "Failed to create task", http.StatusInternalServerError)
+		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create task"})
 		return
 	}

-	// 保存されたタスクの詳細を取得
 	savedTask, err := h.Repo.GetTaskByID(task.ID)
 	if err != nil {
-		http.Error(w, "Failed to retrieve saved task", http.StatusInternalServerError)
+		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to retrieve saved task"})
 		return
 	}

-	// 保存されたタスクの詳細をJSONとしてレスポンスに書き込む
-	w.Header().Set("Content-Type", "application/json")
-	w.WriteHeader(http.StatusCreated)
-	json.NewEncoder(w).Encode(savedTask)
+	c.JSON(http.StatusCreated, savedTask)
 }

 // GET /tasks に対するハンドラー関数です。
-func (h *TaskHandler) GetAllTasks(w http.ResponseWriter, r *http.Request) {
+func (h *TaskHandler) GetAllTasks(c *gin.Context) {
 	tasks, err := h.Repo.GetAllTasks()
 	if err != nil {
-		http.Error(w, "Failed to retrieve tasks", http.StatusInternalServerError)
+		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to retrieve tasks"})
 		return
 	}

-	// 取得したタスクをJSONとしてレスポンスに書き込む
-	w.Header().Set("Content-Type", "application/json")
-	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(tasks)
+	c.JSON(http.StatusOK, tasks)
 }

 // GetTask - GET /tasks/{id} に対するハンドラー関数です。
-func (h *TaskHandler) GetTask(w http.ResponseWriter, r *http.Request) {
-	// URLからタスクIDを取得
-	vars := mux.Vars(r)
-	taskID := vars["id"]
+func (h *TaskHandler) GetTask(c *gin.Context) {
+	taskID := c.Param("id")

-	// データベースからタスクを取得
 	task, err := h.Repo.GetTaskByID(taskID)
 	if err != nil {
-		http.Error(w, "Failed to retrieve task", http.StatusInternalServerError)
+		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to retrieve task"})
 		return
 	}

-	// 取得したタスクの詳細をJSONとしてレスポンスに書き込む
-	w.Header().Set("Content-Type", "application/json")
-	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(task)
+	c.JSON(http.StatusOK, task)
 }

 // UpdateTask - PUT /tasks/{id} に対するハンドラー関数です。
-func (h *TaskHandler) UpdateTask(w http.ResponseWriter, r *http.Request) {
-	// URLからタスクIDを取得
-	vars := mux.Vars(r)
-	taskID := vars["id"]
+func (h *TaskHandler) UpdateTask(c *gin.Context) {
+	taskID := c.Param("id")

 	var task model.Task
-	if err := json.NewDecoder(r.Body).Decode(&task); err != nil {
-		http.Error(w, "Invalid request body", http.StatusBadRequest)
+	if err := c.BindJSON(&task); err != nil {
+		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})
 		return
 	}
 	task.ID = taskID

-	// データベースにタスクを更新
 	if err := h.Repo.UpdateTask(&task); err != nil {
-		http.Error(w, "Failed to update task", http.StatusInternalServerError)
+		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update task"})
 		return
 	}

-	// 更新されたタスクの詳細を取得
 	updatedTask, err := h.Repo.GetTaskByID(taskID)
 	if err != nil {
-		http.Error(w, "Failed to retrieve updated task", http.StatusInternalServerError)
+		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to retrieve updated task"})
 		return
 	}

-	// 更新されたタスクの詳細をJSONとしてレスポンスに書き込む
-	w.Header().Set("Content-Type", "application/json")
-	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(updatedTask)
+	c.JSON(http.StatusOK, updatedTask)
 }

 // DeleteTask - DELETE /tasks/{id} に対するハンドラー関数です。
-func (h *TaskHandler) DeleteTask(w http.ResponseWriter, r *http.Request) {
-	// URLからタスクIDを取得
-	vars := mux.Vars(r)
-	taskID := vars["id"]
+func (h *TaskHandler) DeleteTask(c *gin.Context) {
+	taskID := c.Param("id")

-	// データベースからタスクを削除
 	if err := h.Repo.DeleteTask(taskID); err != nil {
-		http.Error(w, "Failed to delete task", http.StatusInternalServerError)
+		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete task"})
 		return
 	}

-	// 削除成功のレスポンスを返す
-	w.WriteHeader(http.StatusNoContent)
+	c.Status(http.StatusNoContent)
 }

```

## main.go

`main.go`は、Go 言語におけるアプリケーションの起点（エントリポイント）としての重要な役割を担っています。このファイルは、プログラムの実行が開始される場所であり、アプリケーションの初期設定、依存関係の構築、およびアプリケーションの主要な実行フローを定義します。具体的には、データベース接続の設定、HTTP サーバーの初期化とルーティングの設定、ミドルウェアの構成、およびサーバーの起動などが main.go 内で行われます。このファイルは、アプリケーションの他のすべてのコンポーネントを統合し、プログラムの実行を管理する中心的な場所となります。

# main.go の変更点

## フレームワークの変更

以前は`gorilla/mux`を使用して HTTP リクエストのルーティングを行っていましたが、新しいコードでは`gin-gonic/gin`フレームワークを採用しています。

## データベース接続の更新

データベース接続の初期化方法が変更され、`config.GetDB()`から`config.InitDB()`へと更新されました。

## CORS 設定の導入

新しいコードでは、CORS（Cross-Origin Resource Sharing）設定を追加して、異なるオリジンからのリクエストを許可しています。

## ルートの設定

HTTP リクエストのルーティングが Gin フレームワークのメソッドを使用して設定されています。

## サーバーの起動方法の変更

サーバーの起動方法が Gin フレームワークによるものに変更されています。

これらの変更により、`main.go`はより効率的かつシンプルなコードになり、Gin フレームワークの強力な機能を活用してサーバーの設定と HTTP リクエストの処理を行うことが可能になりました。

## 変更前後のコード比較

```diff
diff --git a/main.go b/main.go
index bbcf1fe..a489cda 100644
--- a/main.go
+++ b/main.go
@@ -1,36 +1,35 @@
 package main

 import (
-	"log"
-	"net/http"
-
-	"github.com/gorilla/handlers"
-	"github.com/gorilla/mux"
+	"github.com/gin-contrib/cors"
+	"github.com/gin-gonic/gin"
 	"github.com/tonbiattack/go-task-management-api/pkg/config"
 	"github.com/tonbiattack/go-task-management-api/pkg/handler"
 	"github.com/tonbiattack/go-task-management-api/pkg/repository"
 )

 func main() {
-	db := config.GetDB()
+	db := config.InitDB()
 	taskRepo := repository.NewTaskRepository(db)
 	taskHandler := handler.NewTaskHandler(taskRepo)
-	router := mux.NewRouter()

-	router.HandleFunc("/tasks", taskHandler.GetAllTasks).Methods("GET")
-	router.HandleFunc("/task", taskHandler.CreateTask).Methods("POST")
-	router.HandleFunc("/task/{id}", taskHandler.GetTask).Methods("GET")
-	router.HandleFunc("/task/{id}", taskHandler.UpdateTask).Methods("PUT")
-	router.HandleFunc("/task/{id}", taskHandler.DeleteTask).Methods("DELETE")
+	router := gin.Default()
+
+	// CORS設定
+	router.Use(cors.New(cors.Config{
+		AllowOrigins:     []string{"http://localhost:5173"},
+		AllowMethods:     []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
+		AllowHeaders:     []string{"Origin", "Content-Type", "Authorization"},
+		AllowCredentials: true,
+	}))

-	corsMiddleware := handlers.CORS(
-		handlers.AllowedHeaders([]string{"X-Requested-With", "Content-Type", "Authorization"}),
-		handlers.AllowedMethods([]string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}),
-		handlers.AllowedOrigins([]string{"http://localhost:5173"}), // viteアプリのホスト
-	)
+	// ルートの設定
+	router.GET("/tasks", taskHandler.GetAllTasks)
+	router.POST("/task", taskHandler.CreateTask)
+	router.GET("/task/:id", taskHandler.GetTask)
+	router.PUT("/task/:id", taskHandler.UpdateTask)
+	router.DELETE("/task/:id", taskHandler.DeleteTask)

-	log.Println("Server is running on port 8080...")
-	if err := http.ListenAndServe(":8080", corsMiddleware(router)); err != nil {
-		log.Fatal(err)
-	}
+	// サーバーの起動
+	router.Run(":8080")
 }
```

# まとめ

本記事では、Go 言語を用いた開発プロセスにおいて、フレームワーク「Gin」と ORM「GORM」の導入がいかに効果的かを詳細に解説しました。これらのツールを導入することで、従来の「素の Go」による開発に比べ、大幅な効率化とコードの品質向上を実現することができます。

フレームワークと ORM の導入は、特に大規模なプロジェクトや複雑なデータハンドリングが必要な場合に、コードの管理や拡張性の面で顕著なメリットを提供します。本記事で紹介した例題のタスク管理アプリを通じて、これらの技術の実装方法とその効果を具体的に見ることができました。

Gin と GORM を活用することで、Go 言語でのアプリケーション開発がより強力かつ効率的になります。これらのツールは、開発者が直面する多くの課題に対して効果的な解決策を提供し、Go 言語の持つポテンシャルを最大限に引き出すことができます。

最後に、本記事が Go 言語を用いたアプリケーション開発におけるあなたのガイドとなり、より生産的で品質の高い開発を実現するための一助となれば幸いです。