REST API với Gin Framework

85 phút

REST API với Gin Framework

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