A Final Step, Connect Database And The Seeder (Part 3)

Hey there! Welcome back to our Golang API series. In Part 2, we set up the basic structure and routing for our API. Now, it’s time to level up by adding JWT-based authentication and database migrations. Let’s get started!

Setting Up JWT Authe…


This content originally appeared on DEV Community and was authored by Sheena Zien

Hey there! Welcome back to our Golang API series. In Part 2, we set up the basic structure and routing for our API. Now, it's time to level up by adding JWT-based authentication and database migrations. Let's get started!

Setting Up JWT Authentication

First, let's install the JWT package:

go get github.com/gofiber/contrib/jwt

Update Router to Use JWT Middleware

Next, we'll update our router to include routes that require JWT authentication. Update router/router.go:

package router

import (
    "your_project/pkg/controllers"
    "your_project/pkg/middleware"

    "github.com/gofiber/fiber/v2"
    "github.com/gofiber/fiber/v2/middleware/cors"
)

func SetupRouter(app *fiber.App) {
    app.Use(cors.New())

    // Guest route
    app.Get("/", func(c *fiber.Ctx) error {
        return c.SendString("Hello, World!")
    })
    loginController := controllers.LoginController{}
    app.Post("/login", loginController.Login)

    // The middleware
    p := config.Config("APP_SCREET")
    app.Use(jwtware.New(jwtware.Config{
        SigningKey: jwtware.SigningKey{Key: []byte(p)},
    }))

    // Protected route
    app.Get("/profile", loginController.Profile)
}

Create The Controller

Let's create a LoginController that has a Login and Profile function in pkg/controllers/login-controller.go:

package controllers

import (
    "your_project/db"
    "your_project/pkg/models"
    "your_project/pkg/utils"
    "github.com/gofiber/fiber/v2"
    "golang.org/x/crypto/bcrypt"
)

type LoginController struct {
}

func (s LoginController) Login(c *fiber.Ctx) error {
    var input struct {
        Email    string `json:"email"`
        Password string `json:"password"`
    }
    if err := c.BodyParser(&input); err != nil {
        return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": err.Error()})
    }

    var user models.User
    if err := db.DB.Where("email = ?", input.Email).First(&user).Error; err != nil {
        return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Invalid credentials"})
    }

    if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(input.Password)); err != nil {
        return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Invalid credentials"})
    }

    token, err := utils.GenerateJWT(user.ID)
    if err != nil {
        return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
    }

    return c.JSON(fiber.Map{"token": token})
}

func (s LoginController) Profile(c *fiber.Ctx) error {
    userID := c.Locals("user_id").(uint)
    var user models.User
    if err := db.DB.First(&user, userID).Error; err != nil {
        return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
    }

    return c.JSON(user)
}

Create User Model

Ensure your user model has the necessary fields for registration and authentication. Update pkg/models/user.go:

package models

import "gorm.io/gorm"

type User struct {
    gorm.Model
    Name     string `json:"name"`
    Email    string `json:"email" gorm:"unique"`
    Password string `json:"-"`
}

Create JWT Utility

We'll create a utility function to generate JWT tokens. Create pkg/utils/jwt.go:

package utils

import (
    "time"

    "github.com/golang-jwt/jwt"
    "your_project/config"
)

func GenerateJWT(userID uint) (string, error) {
    secret := config.Config("APP_SECRET")
    claims := jwt.MapClaims{
        "user_id": userID,
        "exp":     time.Now().Add(time.Hour * 72).Unix(),
    }
    token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
    return token.SignedString([]byte(secret))
}

Setting Up Database Migrations with Dbmate

Install Dbmate

go get github.com/amacneil/dbmate

Create Migration File

Create a migration file with make create-migration command then you can add the file name users this is will be generate timestamp_users.sql inside db/migrations directory, then you can the sql code with the following content:

-- migrate:up
CREATE SEQUENCE users_id_seq START WITH 1;
CREATE TABLE "users"(
    "id" int8 NOT NULL DEFAULT nextval('users_id_seq'::regclass),
    "email" TEXT,
    "password" TEXT,
    "created_at" timestamptz,
    "updated_at" timestamptz,
    "deleted_at" timestamptz,
    PRIMARY KEY("id"),
    UNIQUE("email")
);

-- migrate:down
DROP TABLE "users";
DROP SEQUENCE users_id_seq;

Running Migrations

make migrate

Create Seeder File

Let's create a seeder to populate our database with initial data, update your main.go

func main() {
    // other code ...
    app := fiber.New()
    db.ConnectDB()
    Seed()
   // other code ...
}

func Seed() {
    password, err := bcrypt.GenerateFromPassword([]byte("password"), bcrypt.DefaultCost)
    if err != nil {
        log.Fatalf("Failed to hash password: %v", err)
    }

    user := models.User{
        Name:     "Admin",
        Email:    "admin@example.com",
        Password: string(password),
    }

    if err := db.DB.Create(&user).Error; err != nil {
        log.Fatalf("Failed to seed user: %v", err)
    }
}

Running the Project

With all the setup complete, you can now run your project. Open your terminal and run:

make watch

This will start the Fiber server, and you can now access your API at http://localhost:3000/.
And we have api in our application is:

We've completed the last part 🚀

Stay tuned on this repository where we'll continue to enhance our boilerplate, add more features, and improve our project structure even further. Happy coding!


This content originally appeared on DEV Community and was authored by Sheena Zien


Print Share Comment Cite Upload Translate Updates
APA

Sheena Zien | Sciencx (2024-07-27T12:06:33+00:00) A Final Step, Connect Database And The Seeder (Part 3). Retrieved from https://www.scien.cx/2024/07/27/a-final-step-connect-database-and-the-seeder-part-3/

MLA
" » A Final Step, Connect Database And The Seeder (Part 3)." Sheena Zien | Sciencx - Saturday July 27, 2024, https://www.scien.cx/2024/07/27/a-final-step-connect-database-and-the-seeder-part-3/
HARVARD
Sheena Zien | Sciencx Saturday July 27, 2024 » A Final Step, Connect Database And The Seeder (Part 3)., viewed ,<https://www.scien.cx/2024/07/27/a-final-step-connect-database-and-the-seeder-part-3/>
VANCOUVER
Sheena Zien | Sciencx - » A Final Step, Connect Database And The Seeder (Part 3). [Internet]. [Accessed ]. Available from: https://www.scien.cx/2024/07/27/a-final-step-connect-database-and-the-seeder-part-3/
CHICAGO
" » A Final Step, Connect Database And The Seeder (Part 3)." Sheena Zien | Sciencx - Accessed . https://www.scien.cx/2024/07/27/a-final-step-connect-database-and-the-seeder-part-3/
IEEE
" » A Final Step, Connect Database And The Seeder (Part 3)." Sheena Zien | Sciencx [Online]. Available: https://www.scien.cx/2024/07/27/a-final-step-connect-database-and-the-seeder-part-3/. [Accessed: ]
rf:citation
» A Final Step, Connect Database And The Seeder (Part 3) | Sheena Zien | Sciencx | https://www.scien.cx/2024/07/27/a-final-step-connect-database-and-the-seeder-part-3/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.