Gin RESTful API — 任务管理 Todo

知识库
知识库文档
/tech-stacks/gin/examples/Gin RESTful API — 任务管理 Todo.md

文档

Gin RESTful API — 任务管理 Todo

目标

使用 Gin 框架快速搭建 Todo 任务 CRUD API,演示路由分组、参数绑定、中间件。

完整代码

package main

import (
	"net/http"
	"strconv"
	"sync"
	"time"

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

// Todo 模型
type Todo struct {
	ID        int       `json:"id"`
	Title     string    `json:"title" binding:"required"`
	Completed bool      `json:"completed"`
	CreatedAt time.Time `json:"createdAt"`
}

var (
	todos   = []Todo{}
	nextID  = 1
	mu      sync.Mutex
)

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

	// 分组路由
	v1 := r.Group("/api/v1")
	{
		v1.GET("/todos", getTodos)
		v1.GET("/todos/:id", getTodo)
		v1.POST("/todos", createTodo)
		v1.PUT("/todos/:id", updateTodo)
		v1.DELETE("/todos/:id", deleteTodo)
	}

	r.Run(":8080")
}

func getTodos(c *gin.Context) {
	mu.Lock()
	defer mu.Unlock()
	c.JSON(http.StatusOK, gin.H{"count": len(todos), "data": todos})
}

func getTodo(c *gin.Context) {
	id, _ := strconv.Atoi(c.Param("id"))
	mu.Lock()
	defer mu.Unlock()
	for _, t := range todos {
		if t.ID == id {
			c.JSON(http.StatusOK, t)
			return
		}
	}
	c.JSON(http.StatusNotFound, gin.H{"error": "任务不存在"})
}

func createTodo(c *gin.Context) {
	var todo Todo
	if err := c.ShouldBindJSON(&todo); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	mu.Lock()
	todo.ID = nextID
	nextID++
	todo.CreatedAt = time.Now()
	todos = append(todos, todo)
	mu.Unlock()
	c.JSON(http.StatusCreated, todo)
}

func updateTodo(c *gin.Context) {
	id, _ := strconv.Atoi(c.Param("id"))
	var input Todo
	if err := c.ShouldBindJSON(&input); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	mu.Lock()
	defer mu.Unlock()
	for i, t := range todos {
		if t.ID == id {
			todos[i].Title = input.Title
			todos[i].Completed = input.Completed
			c.JSON(http.StatusOK, todos[i])
			return
		}
	}
	c.JSON(http.StatusNotFound, gin.H{"error": "任务不存在"})
}

func deleteTodo(c *gin.Context) {
	id, _ := strconv.Atoi(c.Param("id"))
	mu.Lock()
	defer mu.Unlock()
	for i, t := range todos {
		if t.ID == id {
			todos = append(todos[:i], todos[i+1:]...)
			c.JSON(http.StatusOK, gin.H{"message": "已删除"})
			return
		}
	}
	c.JSON(http.StatusNotFound, gin.H{"error": "任务不存在"})
}

运行步骤

go mod init todo-gin
go get github.com/gin-gonic/gin
go run main.go

测试

# 新增任务
curl -X POST http://localhost:8080/api/v1/todos \
  -H "Content-Type: application/json" \
  -d '{"title":"完成毕设论文"}'

# 获取全部
curl http://localhost:8080/api/v1/todos

# 更新为已完成
curl -X PUT http://localhost:8080/api/v1/todos/1 \
  -H "Content-Type: application/json" \
  -d '{"title":"完成毕设论文","completed":true}'

# 删除
curl -X DELETE http://localhost:8080/api/v1/todos/1

预期输出

  • Gin 启动打印路由表,每个请求自动输出彩色日志
  • JSON 绑定 binding:"required" 自动校验,缺失 title 返回 400
  • 并发安全:sync.Mutex 保护共享切片

信息

路径
/tech-stacks/gin/examples/Gin RESTful API — 任务管理 Todo.md
更新时间
2026/5/30