今回は、MySQL(MariaDB)を使ってReactとGo言語を連携させてTodoアプリを作る方法を作ってみました。
アプリ作成の方針
MySQL・Go(バックエンド)・React(フロントエンド)を連携させたTodoアプリの構成は、モダンなフルスタック構成の代表例です。
ここでは、全体像 → 構成 → 実装手順 → コード例 の順で分かりやすく解説します。
🧩 全体構成イメージ
[React] ←→ [Go REST API] ←→ [MySQL Database]
React:ユーザーがTodoを追加・削除・完了チェックできるUI
Go:APIサーバー(JSON形式でデータ送受信)
MySQL:Todoデータを永続化
⚙️ 環境構成例
| コンポーネント | 使用する技術 |
|---|---|
| フロントエンド | React (Vite or CRA) |
| バックエンド | Go (net/http + gorilla/mux or Gin) |
| データベース | MySQL |
| ORM (任意) | GORM(GoのORM) |
| 通信形式 | REST API(JSON) |
🪜 手順概要
① MySQLセットアップ
CREATE DATABASE todo_app;
USE todo_app;
CREATE TABLE todos (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
completed BOOLEAN DEFAULT FALSE
);
② Go(バックエンド)側の構築
下記のように、コマンドを入力してパッケージをインストールします。
cd backend
go mod init backend
go get gorm.io/driver/mysql
go get github.com/gorilla/mux
go get github.com/rs/cors
go mod tidy
Go言語のWebサーバ起動は下記のコマンドを実行
go run main.go
ディレクトリ構成例
backend/
├── main.go
├── go.mod
├── handlers/
│ └── todo.go
├── models/
│ └── todo.go
└── db/
└── db.go
1. GORMを使ってDB接続
go get gorm.io/gorm gorm.io/driver/mysql github.com/gorilla/mux cors
db/db.go
package db
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
var DB *gorm.DB
func Connect() {
dsn := "root:password@tcp(127.0.0.1:3306)/todo_app?charset=utf8mb4&parseTime=True&loc=Local"
database, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic("DB接続に失敗しました: " + err.Error())
}
DB = database
}
root:password@tcp(127.0.0.1:3306)/todo_app?charset=utf8mb4&parseTime=True&loc=Local について説明します。
この部分は MySQLに接続するための「DSN(Data Source Name)」 と呼ばれる設定文字列です。
Go(GORMやMySQLドライバ)が「どのサーバーの、どのデータベースに、どんな設定で接続するか」を指定しています。
🔹 ① root:password
ユーザー名とパスワード
root → MySQLのユーザー名(デフォルトの管理者ユーザー)
password → そのユーザーのパスワード
つまり「MySQLにログインするための認証情報」です。
#####🔹 ② @tcp(127.0.0.1:3306)
接続先(ホストとポート)
tcp → TCP接続を使う(MySQLは通常TCPで通信)
127.0.0.1 → ローカル(あなたのPC)を指すIPアドレス
3306 → MySQLの標準ポート番号
つまり「自分のパソコンのMySQLサーバーにTCPで接続する」という意味です。
🔹 ③ /todo_app
データベース名
ここで指定されたデータベースを使います。
この場合は todo_app という名前のデータベースです。
🔹 ④ ?charset=utf8mb4&parseTime=True&loc=Local
接続オプション(パラメータ)
| パラメータ | 意味 |
|---|---|
charset=utf8mb4 |
MySQLで日本語や絵文字も扱える文字コード設定 |
parseTime=True |
DATETIME/TIMESTAMP型を自動的にGoのtime.Time型として扱う |
loc=Local |
タイムゾーンをローカル(日本時間など)に設定 |
2. モデル定義
models/todo.go
package models
import "gorm.io/gorm"
type Todo struct {
gorm.Model
Title string `json:"title"`
Completed bool `json:"completed"`
}
3. ハンドラー(APIエンドポイント)
handlers/todo.go
package handlers
import (
"encoding/json"
"net/http"
"github.com/gorilla/mux"
"your_project/db"
"your_project/models"
)
func GetTodos(w http.ResponseWriter, r *http.Request) {
var todos []models.Todo
db.DB.Find(&todos)
json.NewEncoder(w).Encode(todos)
}
func CreateTodo(w http.ResponseWriter, r *http.Request) {
var todo models.Todo
json.NewDecoder(r.Body).Decode(&todo)
db.DB.Create(&todo)
json.NewEncoder(w).Encode(todo)
}
func ToggleTodo(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
var todo models.Todo
db.DB.First(&todo, params["id"])
todo.Completed = !todo.Completed
db.DB.Save(&todo)
json.NewEncoder(w).Encode(todo)
}
func DeleteTodo(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
db.DB.Delete(&models.Todo{}, params["id"])
w.WriteHeader(http.StatusNoContent)
}
4. main.go にルーティング設定
package main
import (
"log"
"net/http"
"github.com/gorilla/mux"
"github.com/rs/cors"
"your_project/db"
"your_project/handlers"
"your_project/models"
)
func main() {
db.Connect()
db.DB.AutoMigrate(&models.Todo{})
r := mux.NewRouter()
r.HandleFunc("/todos", handlers.GetTodos).Methods("GET")
r.HandleFunc("/todos", handlers.CreateTodo).Methods("POST")
r.HandleFunc("/todos/{id}", handlers.ToggleTodo).Methods("PUT")
r.HandleFunc("/todos/{id}", handlers.DeleteTodo).Methods("DELETE")
handler := cors.AllowAll().Handler(r)
log.Println("Server running on :8080")
log.Fatal(http.ListenAndServe(":8080", handler))
}
③ React(フロントエンド)側
npm create vite@latest frontend -- --template react
cd frontend
npm install axios
npm run dev
src/App.jsx
import { useEffect, useState } from "react";
import axios from "axios";
const API_URL = "http://localhost:8080/todos";
export default function App() {
const [todos, setTodos] = useState([]);
const [title, setTitle] = useState("");
useEffect(() => {
axios.get(API_URL).then((res) => setTodos(res.data));
}, []);
const addTodo = async () => {
const res = await axios.post(API_URL, { title });
setTodos([...todos, res.data]);
setTitle("");
};
const toggleTodo = async (id) => {
const res = await axios.put(`${API_URL}/${id}`);
setTodos(todos.map((t) => (t.id === id ? res.data : t)));
};
const deleteTodo = async (id) => {
await axios.delete(`${API_URL}/${id}`);
setTodos(todos.filter((t) => t.id !== id));
};
return (
<div style={{ maxWidth: 400, margin: "auto" }}>
<h1>Todo List</h1>
<input value={title} onChange={(e) => setTitle(e.target.value)} />
<button onClick={addTodo}>追加</button>
<ul>
{todos.map((todo) => (
<li key={todo.ID}>
<span
onClick={() => toggleTodo(todo.ID)}
style={{
textDecoration: todo.completed ? "line-through" : "none",
cursor: "pointer",
}}
>
{todo.title}
</span>
<button onClick={() => deleteTodo(todo.ID)}>削除</button>
</li>
))}
</ul>
</div>
);
}
🚀 実行手順まとめ
MySQL起動 → CREATE DATABASE todo_app;
Goサーバー起動 → go run main.go
React起動 → npm run dev
ブラウザで http://localhost:5173
にアクセス
→ Todoアプリ完成🎉
Go言語関連
サイト