2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Go言語で学ぶWebアプリケーション開発2:[データベース連携&認証機能の追加]

Last updated at Posted at 2025-03-02

はじめに

前回の記事では、Go + Ginを使ったバックエンドとReact + Viteを使ったフロントエンドで作成したシンプルなToDoアプリを作成しました。
今回はそこに、データベース連携(SQLite + GORM)とJWT認証機能の追加を行い、より実用的なWebアプリケーションに発展させます。

対象読者

  • Goでデータベースと連携したWebアプリを作成したい方
  • JWT認証を導入し、ログイン機能を実装したい方
  • フルスタック開発を学びたい方

目次

  1. データベース連携(GORM + SQLite)
    • GORMのセットアップ
    • モデルの定義とマイグレーション
    • CRUD操作の実装
  2. 認証機能(JWT)
    • ユーザーモデルの作成
    • ログインAPIの実装
    • JWTトークンの発行と認証
  3. フロントエンドとの統合
    • 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アプリケーションに近づけました。
次はさらにユーザー管理やロールベース認証の追加 をまとめていこうと思います!

2
2
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
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?