📖 Golang Toàn tập - REST API với Gin Framework
85 phút

REST API với Gin Framework

Giới thiệu Gin

Gin là web framework hiệu suất cao cho Go.

Cài đặt

go get -u github.com/gin-gonic/gin

Ứng dụng cơ bản

package main

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

func main() {
    r := gin.Default()

    r.GET("/ping", func(c *gin.Context) {
        c.JSON(200, gin.H{
            "message": "pong",
        })
    })

    r.Run(":8080")
}

Routing

HTTP Methods

r.GET("/users", getUsers)
r.POST("/users", createUser)
r.PUT("/users/:id", updateUser)
r.DELETE("/users/:id", deleteUser)
r.PATCH("/users/:id", patchUser)

Route groups

v1 := r.Group("/api/v1")
{
    v1.GET("/users", getUsers)
    v1.POST("/users", createUser)
}

auth := v1.Group("/admin")
auth.Use(AuthMiddleware())
{
    auth.GET("/stats", getStats)
}

Request Handling

Path parameters

r.GET("/users/:id", func(c *gin.Context) {
    id := c.Param("id")
    c.JSON(200, gin.H{"id": id})
})

Query parameters

r.GET("/search", func(c *gin.Context) {
    q := c.Query("q")
    page := c.DefaultQuery("page", "1")
    c.JSON(200, gin.H{"q": q, "page": page})
})

JSON binding

type CreateUserRequest struct {
    Name  string `json:"name" binding:"required"`
    Email string `json:"email" binding:"required,email"`
    Age   int    `json:"age" binding:"gte=0,lte=150"`
}

r.POST("/users", func(c *gin.Context) {
    var req CreateUserRequest
    if err := c.ShouldBindJSON(&req); err != nil {
        c.JSON(400, gin.H{"error": err.Error()})
        return
    }
    c.JSON(201, req)
})

Middleware

Custom middleware

func AuthMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        token := c.GetHeader("Authorization")
        if token == "" {
            c.AbortWithStatusJSON(401, gin.H{"error": "unauthorized"})
            return
        }
        c.Set("userID", 123)
        c.Next()
    }
}

CORS

import "github.com/gin-contrib/cors"

r.Use(cors.Default())

Project Structure

myapi/
├── main.go
├── go.mod
├── internal/
│   ├── handlers/
│   │   └── user.go
│   ├── models/
│   │   └── user.go
│   ├── services/
│   │   └── user.go
│   ├── repositories/
│   │   └── user.go
│   └── middleware/
│       └── auth.go
└── pkg/
    └── database/
        └── db.go

Full Example

Model

package models

import "time"

type User struct {
    ID        uint      `json:"id" gorm:"primaryKey"`
    Name      string    `json:"name" binding:"required"`
    Email     string    `json:"email" binding:"required,email" gorm:"unique"`
    CreatedAt time.Time `json:"created_at"`
    UpdatedAt time.Time `json:"updated_at"`
}

Handler

package handlers

import (
    "net/http"
    "github.com/gin-gonic/gin"
    "myapi/internal/models"
)

type UserHandler struct {
    // dependencies
}

func (h *UserHandler) GetUsers(c *gin.Context) {
    users := []models.User{}
    c.JSON(http.StatusOK, users)
}

func (h *UserHandler) CreateUser(c *gin.Context) {
    var user models.User
    if err := c.ShouldBindJSON(&user); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }
    c.JSON(http.StatusCreated, user)
}

Main

package main

import (
    "github.com/gin-gonic/gin"
    "myapi/internal/handlers"
)

func main() {
    r := gin.Default()

    userHandler := &handlers.UserHandler{}

    api := r.Group("/api/v1")
    {
        users := api.Group("/users")
        {
            users.GET("", userHandler.GetUsers)
            users.POST("", userHandler.CreateUser)
            users.GET("/:id", userHandler.GetUser)
            users.PUT("/:id", userHandler.UpdateUser)
            users.DELETE("/:id", userHandler.DeleteUser)
        }
    }

    r.Run(":8080")
}

Bài tập thực hành

Hãy tạo REST API hoàn chỉnh cho quản lý sản phẩm!

📝 Bài tập (1)

  1. Tạo REST API với Gin