🤖
Go言語で学ぶWebアプリケーション開発2:[データベース連携&認証機能の追加]
はじめに
前回の記事では、Go + Ginを使ったバックエンドとReact + Viteを使ったフロントエンドで作成したシンプルなToDoアプリを作成しました。
今回はそこに、データベース連携(SQLite + GORM)とJWT認証機能の追加を行い、より実用的なWebアプリケーションに発展させます。
対象読者
- Goでデータベースと連携したWebアプリを作成したい方
- JWT認証を導入し、ログイン機能を実装したい方
- フルスタック開発を学びたい方
目次
- データベース連携(GORM + SQLite)
- GORMのセットアップ
- モデルの定義とマイグレーション
- CRUD操作の実装
- 認証機能(JWT)
- ユーザーモデルの作成
- ログインAPIの実装
- JWTトークンの発行と認証
- フロントエンドとの統合
- Reactからの認証リクエスト
- 認証されたユーザーのみAPIにアクセス可能にする
1. データベース連携(GORM + SQLite)
1.1 GORM のセットアップ
まず、GORMとSQLiteドライバをインストールします。
go get -u gorm.io/gorm
go get -u gorm.io/driver/sqlite
1.2 モデルの定義とマイグレーション
データベースに格納するTodoモデルを定義します。
models/todo.go
package models
import "gorm.io/gorm"
type Todo struct {
ID uint `gorm:"primaryKey"`
Task string `json:"task"`
Status bool `json:"status"`
}
データベースの接続とマイグレーションを行います。
database/database.go
package database
import (
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"log"
"models"
)
var DB *gorm.DB
func InitDatabase() {
var err error
DB, err = gorm.Open(sqlite.Open("app.db"), &gorm.Config{})
if err != nil {
log.Fatal("Failed to connect database")
}
DB.AutoMigrate(&models.Todo{})
}
main.goでデータベースを初期化します。
database.InitDatabase()
1.3 CRUD操作の実装
controllers/todo_controller.go
package controllers
import (
"github.com/gin-gonic/gin"
"net/http"
"database"
"models"
)
func GetTodos(c *gin.Context) {
var todos []models.Todo
database.DB.Find(&todos)
c.JSON(http.StatusOK, todos)
}
func CreateTodo(c *gin.Context) {
var newTodo models.Todo
if err := c.ShouldBindJSON(&newTodo); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
database.DB.Create(&newTodo)
c.JSON(http.StatusCreated, newTodo)
}
ルーティングの設定を行います。
router.GET("/api/todos", controllers.GetTodos)
router.POST("/api/todos", controllers.CreateTodo)
2. 認証機能(JWT)
2.1 ユーザーモデルの作成
models/user.go
package models
type User struct {
ID uint `gorm:"primaryKey"`
Username string `json:"username"`
Password string `json:"password"`
}
2.2 ログインAPIの実装
controllers/auth_controller.go
package controllers
import (
"github.com/gin-gonic/gin"
"net/http"
"database"
"models"
"time"
"github.com/golang-jwt/jwt/v4"
)
type LoginRequest struct {
Username string `json:"username"`
Password string `json:"password"`
}
func Login(c *gin.Context) {
var req LoginRequest
var user models.User
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
database.DB.Where("username = ?", req.Username).First(&user)
if user.ID == 0 || user.Password != req.Password {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid credentials"})
return
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"username": user.Username,
"exp": time.Now().Add(time.Hour * 2).Unix(),
})
tokenString, _ := token.SignedString([]byte("secret"))
c.JSON(http.StatusOK, gin.H{"token": tokenString})
}
ルーティングを設定します。
router.POST("/api/login", controllers.Login)
3. フロントエンドとの統合
3.1 React からの認証リクエスト
src/Login.jsx
import { useState } from "react";
import axios from "axios";
function Login() {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const handleLogin = async () => {
const response = await axios.post("http://localhost:8080/api/login", { username, password });
localStorage.setItem("token", response.data.token);
};
return (
<div>
<input type="text" placeholder="Username" onChange={(e) => setUsername(e.target.value)} />
<input type="password" placeholder="Password" onChange={(e) => setPassword(e.target.value)} />
<button onClick={handleLogin}>Login</button>
</div>
);
}
export default Login;
まとめ
今回は、GORMを使ったデータベース連携とJWT認証機能の追加を行い、より実用的なWebアプリケーションに近づけました。
次はさらにユーザー管理やロールベース認証の追加 をまとめていこうと思います!
Discussion