🪟 Windows TippsHow to Enable Windows 11 Screen Savers(07.09.2026 um 12:41 Uhr)
🪟 Windows TippsMicrosoft Phone Link Not Showing Messages on Windows 11? Fix It(09.09.2026 um 07:52 Uhr)
⚠️ Malware / Trojaner / VirenPost-DEF CON phishing campaign delivered AMOS and NetSupport malware(24.08.2026 um 09:42 Uhr)
💾 IT Security ToolsHow to Use BloodHound Active Directory Setup Attack Path Analysis(10.09.2026 um 14:35 Uhr)
🕵️ SicherheitslückenCompliance Alert: EU Cyber Resilience Act 24-Hour Reporting Enforced(11.09.2026 um 06:25 Uhr)
🕵️ SicherheitslückenAWS IAM Privilege Escalation: Cheat Sheet And Defense(11.09.2026 um 07:43 Uhr)
🕵️ SicherheitslückenArista warns customers ahead of next week’s security disclosures(02.09.2026 um 23:34 Uhr)
🕵️ SicherheitslückenKARR Security vulnerability(02.09.2026 um 03:15 Uhr)
🪟 Windows TippsHow to Enable Windows 11 Screen Savers(07.09.2026 um 12:41 Uhr)
🪟 Windows TippsMicrosoft Phone Link Not Showing Messages on Windows 11? Fix It(09.09.2026 um 07:52 Uhr)
⚠️ Malware / Trojaner / VirenPost-DEF CON phishing campaign delivered AMOS and NetSupport malware(24.08.2026 um 09:42 Uhr)
💾 IT Security ToolsHow to Use BloodHound Active Directory Setup Attack Path Analysis(10.09.2026 um 14:35 Uhr)
🕵️ SicherheitslückenCompliance Alert: EU Cyber Resilience Act 24-Hour Reporting Enforced(11.09.2026 um 06:25 Uhr)
🕵️ SicherheitslückenAWS IAM Privilege Escalation: Cheat Sheet And Defense(11.09.2026 um 07:43 Uhr)
🕵️ SicherheitslückenArista warns customers ahead of next week’s security disclosures(02.09.2026 um 23:34 Uhr)
🕵️ SicherheitslückenKARR Security vulnerability(02.09.2026 um 03:15 Uhr)

🔧 Programmierung 🕛 vor 1 Jahr 14 Min Lesezeit
0

A CRUD API with Go, using the Gin framework and MongoDB.

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht

Hi, here we want to create a simple and clean RESTful API built with Golang (Gin), MongoDB, and JWT Authentication.

This API allows you to register, log in, and perform user management operations securely.

you can find the source code here :





📦 Features of Project




  • 🔑 User registration and login with secure password hashing

  • 🛡️ JWT-based authentication

  • 🔄 Full ‍‍CRUD operations for users

  • ✅ Input validation using go-playground/validator

  • 📚 Swagger documentation with swaggo/gin-swagger

  • 💾 MongoDB integration using mongo-driver

  • 🧪 Tests for core functionalities



⚙️ Prerequisites

‌Befor starting make sure that you have these :




  • latest version of go

  • postman or curl for api testing







🔨 Initializing a Go project:



First of all create a folder for project :




CODE
mkdir go-crud-api
cd go-crud-api






For initializing a Go project we usually run this command : go mod init . this command create a file (go.mod) in your directory , this file is using for dependency management of your project. so open your terminal & run this command go mod init then write this go mod init github.com/yourusername/go-crud-api in the file if you doesn't create any repo for your project you can just write go mod init my-project then change it to your repo address.




  • we use Gin for creating api :go get -u github.com/gin-gonic/gin









📁 Project structure






CODE
go-crud-api/

├── main.go
├── config/ ← Database settings and ...
│ └── db.go
├── controller/ ← Controllers (logic related to APIs)
│ └── user.go
├── model/ ← Data structures and models
│ └── user.go
├── middleware/ ← Middlewares (like auth)
│ └── authMiddleware.go
├── routes/ ← Routing
│ └── userRoutes.go
├── utils/ ← Helper functions (like ValidateToken)
│ └── jwt.go
├── go.mod / go.sum ← Package information
└── README.md ← Project description












🧠 Explain Code






1. go-crud-api/main.go






CODE
package main

import (
"crud-api-go/config"
"crud-api-go/routes"
"github.com/gin-gonic/gin"
)

func main() {
config.ConnectDB()
router := gin.Default()
routes.UserRoutes(router)
router.Run("localhost:8080")
}







  • The main function is the entry point of our program.


  • config.ConnectDB() : this line calls a function(ConnectDB)from config package. this function is responsible for establishing connection to your database.


  • router := gin.Default() : A router is a core of a web app , it determines how the app responds to different client request at different URL.


  • routes.UserRoutes(router) : This line calls a function userRoutes from the routes package,passing the Gin router as an argument.this function is responsible for defining all the API routes related to users (like creating, reading, updating, and deleting users).


  • router.Run("localhost:8080") : This line starts the Gin web server makes it listen for incoming HTTP requests on the address localhost:8080.







2. go-crud-api/config/db.go



Setting Up Our MongoDB Connection in Go**



Packages We Rely On:





  • time, context: Used for managing timeouts during the database connection process.


  • os, log, fmt: Essential for interacting with the operating system (reading environment variables), logging errors, and printing informational messages.


  • github.com/joho/godotenv: A library for loading environment variables from a .env file.

  • go.mongodb.org/mongo-driver/mongo & go.mongodb.org/mongo-driver/mongo/options: The official Go driver for MongoDB.


  • var DB *mongo.Database : Here, we declare a global variable DB of type *mongo.Database. This allows us to easily access the established database connection from anywhere in our Go application.


  • err := godotenv.Load() : We use the godotenv.Load() function to read key-value pairs from our .env file and make them available as environment variables within our application.





CODE
if err != nil {
log.Fatal("❌ Error loading .env file")
}






If the .env file failed to load the program execution will be halted.




CODE
mongoURI := os.Getenv("MONGO_URI")
databaseName := os.Getenv("DB_NAME")






with os.Getenv we get the environmental variable for connecting to database.



clientOptions := options.Client().ApplyURI(mongoURI) : This line is using for setup connection settings.




CODE
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()






A context is created with a 10-second timeout to prevent the connection from hanging indefinitely. The defer cancel() ensures that the context's resources are released when the function exits.



client, err := mongo.Connect(ctx, clientOptions) : Here, we attempt to establish a connection to our MongoDB instance using the configured clientOptions and the context we created.



DB = client.Database(databaseName) : Finally we setup the database instance, so it's accessible through out the entire application.




CODE
package config

import (
"context"
"fmt"
"log"
"os"
"time"

"github.com/joho/godotenv"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)

var DB *mongo.Database

func ConnectDB() {
// Load environment variables
err := godotenv.Load()
if err != nil {
log.Fatal("❌ Error loading .env file")
}

// Get URI and database name from .env file
mongoURI := os.Getenv("MONGO_URI")
databaseName := os.Getenv("DB_NAME")

if mongoURI == "" {
log.Fatal("❌ MONGO_URI is not set in .env")
}
if databaseName == "" {
log.Fatal("❌ DB_NAME is not set in .env")
}

// Set up connection options
clientOptions := options.Client().ApplyURI(mongoURI)

// Create context with timeout
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

// Connect to MongoDB
client, err := mongo.Connect(ctx, clientOptions)
if err != nil {
log.Fatal("❌ MongoDB connection error:", err)
}

// Ping the database to test connection
err = client.Ping(ctx, nil)
if err != nil {
log.Fatal("❌ MongoDB ping error:", err)
}

fmt.Println("✅ Connected to MongoDB Atlas!")

// Set the selected database
DB = client.Database(databaseName)
}









3. go-crud-api/routes/userRoutes.go



This file is related to defining HTTP routes.we define public routes such as signup & login then we created a group of routes that are connected to the authentication middleware and include CRUD operations on users.




CODE
package routes

import (
"crud-api-go/controller"
"crud-api-go/middleware"

"github.com/gin-gonic/gin"
)

func UserRoutes(router *gin.Engine) {
router.POST("/signup", controller.Signup)
router.POST("/login", controller.Login)

protected := router.Group("/")
protected.Use(middleware.AuthMiddleware())
{
protected.GET("/users", controller.GetUsers)
protected.GET("/users/:id", controller.GetUserByID)
protected.POST("/users", controller.CreateUser)
protected.PUT("/users/:id", controller.UpdateUser)
protected.DELETE("/users/:id",controller.DeleteUser)
}
}







we define a function named UserRoutes.this function will be responsible for defining all the API endpoints related to the users. this function take a pointer to a gin .Engine as an argument. the gin.Engin is the main instance of the Gin router.




  • protected := router.Group("/") : this line creates a new route group using the router.Group("/") method.The / shows that all routes defined within this group will have a common base path.


  • protected.Use(middleware.AuthMiddleware()) : This means that for any request made to the routes defined within this group, the AuthMiddleware() function will be executed first.







4. go-crud-api/model/user.go



Model structures in this file are designed for three purposes: storing data in MongoDB (User), securely responding to clients (UserResponse and AuthResponse), and receiving input from clients for registration, login, or editing.




CODE
package model

import "go.mongodb.org/mongo-driver/bson/primitive"

type User struct {
ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"`
Name string `json:"name" bson:"name" validate:"required,min=2,max=50"`
Email string `json:"email" bson:"email" validate:"required,email"`
Password string `json:"password,omitempty" bson:"password,omitempty" validate:"required,min=6"`
}

type UserResponse struct {
ID primitive.ObjectID `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}

type AuthResponse struct {
Token string `json:"token"`
User UserResponse `json:"user"`
}

type SignupInput struct {
Name string `json:"name" validate:"required"`
Email string `json:"email" validate:"required,email"`
Password string `json:"password" validate:"required"`
}

type LoginInput struct {
Email string `json:"email" validate:"required,email"`
Password string `json:"password" validate:"required"`
}

type CreateUserInput struct {
Name string `json:"name" validate:"required"`
Email string `json:"email" validate:"required,email"`
Password string `json:"password" validate:"required"`
}

type UpdateUserInput struct {
Name string `json:"name" validate:"required,min=2,max=50"`
Email string `json:"email" validate:"required,email"`
}









5. go-crud-api/controller/user.go



In this file we have 5 main controller functions for CRUD operations on users, all written using Gin and connected to the MongoDB database. We utilize input validation, and all requests, except for signup and login, require JWT authentication.




  • First of all we import packages , these packages are for interacting with the MongoDB database, managing time, performing validation, and the Gin framework for handling HTTP requests, config for database access and model for defining data structures.


  • Helper Function and Validation





CODE
func getUserCollection() *mongo.Collection {
return config.DB.Collection("users")
}






This function retrieves the MongoDB collection named users from the existing DB connection in the config package.




CODE
var validate = validator.New()






We use the 'validator' package to check user inputs (e.g., whether fields are required or the email structure is correct).




  • GetUsers : The GetUsers function retrieves a list of users from the database and responds in JSON format.


  • GetUserByID : Retrieving a specific user from the database by ID and responding in JSON format.


  • CreateUser : Creating a new user and saving it to MongoDB.


  • UpdateUser : Updating user information in the database based on the ID.


  • DeleteUser : Deleting a user from the database based on the ID.





CODE
package controller

import (
"context"
"crud-api-go/config"
"crud-api-go/model"
"net/http"
"time"

"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
)

func getUserCollection() *mongo.Collection {
return config.DB.Collection("users")
}

var validate = validator.New()

func GetUsers(c *gin.Context) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

cursur, err := getUserCollection().Find(ctx, bson.M{})
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "error fetching users"})
return
}
defer cursur.Close(ctx)

var users []model.User
if err := cursur.All(ctx, &users); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "error parsing users"})
return
}

var userslist []model.UserResponse
for _, u := range users {
userslist = append(userslist, model.UserResponse{
ID: u.ID,
Name: u.Name,
Email: u.Email,
})
}
c.JSON(http.StatusOK, userslist)

}

func GetUserByID(c *gin.Context) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

idParam := c.Param("id")
objectId, err := primitive.ObjectIDFromHex(idParam)

if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid ID Format"})
return
}

var user model.User
err = getUserCollection().FindOne(ctx, bson.M{"_id": objectId}).Decode(&user)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
return
}
c.JSON(http.StatusOK, user)
}

func CreateUser(c *gin.Context) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

var input model.CreateUserInput
if err := c.BindJSON(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"})
return
}

if err := validate.Struct(input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}

newUser := model.User{
ID: primitive.NewObjectID(),
Name: input.Name,
Email: input.Email,
Password: input.Password,
}

_, err := getUserCollection().InsertOne(ctx, newUser)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create user"})
return
}

c.JSON(http.StatusCreated, model.UserResponse{
ID: newUser.ID,
Name: newUser.Name,
Email: newUser.Email,
})
}

func UpdateUser(c *gin.Context) {
idParam := c.Param("id")

objectId, err := primitive.ObjectIDFromHex(idParam)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid user ID"})
return
}

var updatedUser model.UpdateUserInput
if err := c.BindJSON(&updatedUser); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid JSON"})
return
}

if err := validate.Struct(updatedUser); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

update := bson.M{
"$set": bson.M{
"name": updatedUser.Name,
"email": updatedUser.Email,
},
}

res, err := getUserCollection().UpdateOne(ctx, bson.M{"_id": objectId}, update)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update user"})
return
}

if res.MatchedCount == 0 {
c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
return
}

c.JSON(http.StatusOK, gin.H{"message": "User updated successfully"})
}

func DeleteUser(c *gin.Context) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

idParam := c.Param("id")
objectId, err := primitive.ObjectIDFromHex(idParam)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid ID format"})
return
}

res, err := getUserCollection().DeleteOne(ctx, bson.M{"_id": objectId})
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to delete user"})
return
}

if res.DeletedCount == 0 {
c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
return
}

c.JSON(http.StatusOK, gin.H{"message": "User deleted"})
}









6. go-crud-api/controller/auth.go



In this file, we have two functions: Signup and Login. Signup registers a new user, hashes their password, and generates a JWT. Login verifies the user's email and password and, upon successful authentication, sends back a JWT. This token is subsequently used by the middleware for authentication.



Signup: This function handles new user registration. It takes user information, checks if the email is not already taken, hashes the password, and saves the user to the database. Finally, it returns a JWT token.



Login: This function is used for user login. It receives the email and password, and if they are valid, it generates a JWT token.




CODE
package controller

import (
"context"
"crud-api-go/model"
"crud-api-go/utils"
"net/http"
"strings"
"time"

"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"golang.org/x/crypto/bcrypt"
)

func Signup(c *gin.Context) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

var input model.SignupInput
if err := c.ShouldBindJSON(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"})
return
}

var existingUser model.User
err := getUserCollection().FindOne(ctx, bson.M{"email": input.Email}).Decode(&existingUser)
if err == nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "User already exists"})
return
}

hashedPassword, err := bcrypt.GenerateFromPassword([]byte(input.Password), bcrypt.DefaultCost)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to hash password"})
return
}

newUser := model.User{
ID: primitive.NewObjectID(),
Name: input.Name,
Email: strings.ToLower(input.Email),
Password: string(hashedPassword),
}

_, err = getUserCollection().InsertOne(ctx, newUser)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create user"})
return
}

token, err := utils.GenerateJWT(newUser.Email)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create token"})
return
}

c.JSON(http.StatusCreated, model.AuthResponse{
Token: token,
User: model.UserResponse{
ID: newUser.ID,
Name: newUser.Name,
Email: newUser.Email,
},
})
}


func Login(c *gin.Context) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

var input model.LoginInput
if err := c.ShouldBindJSON(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"})
return
}

var foundUser model.User
err := getUserCollection().FindOne(ctx, bson.M{"email": input.Email}).Decode(&foundUser)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid email or password"})
return
}

err = bcrypt.CompareHashAndPassword([]byte(foundUser.Password), []byte(input.Password))
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid credentials. Please check your email and password"})
return
}

token, err := utils.GenerateJWT(foundUser.Email)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create token"})
return
}

c.JSON(http.StatusOK, model.AuthResponse{
Token: token,
User: model.UserResponse{
ID: foundUser.ID,
Name: foundUser.Name,
Email: foundUser.Email,
},
})
}










7. go-crud-api/middleware/authMiddleware.go



Here we createa middleware to protect sensitive routes that require authentication, using JWT tokens.

This middleware (AuthMiddleware()) checks the Authorization header. If it's in the Bearer <token> format, it extracts the token, validates it using the JWT secret, and if valid, adds the user's email to the context for subsequent use. If there's an issue, the request is aborted.




CODE
package middleware

import (
"crud-api-go/utils"
"net/http"
"strings"
"github.com/gin-gonic/gin"
)

func AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
authHeader := c.GetHeader("Authorization")
if authHeader == "" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization header missing"})
c.Abort()
return
}
const bearerPrefix = "Bearer "
if !strings.HasPrefix(authHeader, bearerPrefix) {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid Authorization header format"})
c.Abort()
return
}
tokenString := strings.TrimPrefix(authHeader, bearerPrefix)
claims, err := utils.ValidateToken(tokenString)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"})
c.Abort()
return
}
c.Set("userEmail", claims.Email)
c.Next()
}
}










8. ‍‍go-crud-api/utils/jwt.go



This file contains two key functions for working with JWT tokens.





  • GenerateJWT is used to create a token with the user's email and a 24-hour expiration time.


  • ValidateToken is used to verify the token's validity and retrieve the information it contains. The HS256 algorithm and an environment variable are used for signing to enhance security.




CODE
package utils

import (
"os"
"time"

"github.com/golang-jwt/jwt/v5"
)

var jwtKey = []byte(os.Getenv("JWT_SECRET"))

type Claims struct {
Email string `json:"email"`
jwt.RegisteredClaims
}

// Generate token
func GenerateJWT(email string) (string, error) {
expirationTime := time.Now().Add(24 * time.Hour)

claims := &Claims{
Email: email,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(expirationTime),
},
}

token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, err := token.SignedString(jwtKey)
if err != nil {
return "", err
}

return tokenString, nil
}

// validate Token
func ValidateToken(tokenString string) (*Claims, error) {
claims := &Claims{}

token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
return jwtKey, nil
})

if err != nil {
return nil, err
}

if !token.Valid {
return nil, jwt.ErrTokenInvalidClaims
}

return claims, nil
}










Now We've reached the end of this tutorial! I hope this guide has been helpful for you in building a simple and secure API with Go, Gin, MongoDB, and JWT.

go-crud-api



Thank you for reading! 🍀

Vollständiger Original-Bericht
Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
2 Quellen
Microsoft Phone Link Not Showing Messages on Windows 11? Fix It
1 Quelle
How to Enable Windows 11 Screen Savers
1 Quelle
Post-DEF CON phishing campaign delivered AMOS and NetSupport malware
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten A CRUD API with Go, using the Gin framework and MongoDB.

Thematisch verwandte Begriffe: CRUD, with, using, framework · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...