[gin]基于切片实现crud
前言
代码参考自《Building Distributed Application in Gin》
需求:设计一个食谱相关的API,数据存放到切片中。
设计模型和API
模型
type Recipe struct {
// 菜品名
Name string `json:"name"`
// 菜品标签,字符串切片
Tags []string `json:"tags"`
// 菜品材料
Ingredients []string `json:"ingredients"`
// 制作步骤
Instructions []string `json:"instructions"`
// 发布时间
PublishedAt time.Time `json:"publishedAt"`
}
API
http method | resource | description |
---|---|---|
GET | /recipes |
返回一列recipe数据 |
POST | /recipes |
创建新食谱 |
PUT | /recipes/{id} |
更新一个已存在的食谱 |
DELETE | /recipes/{id} |
删除一个已存在的食谱 |
GET | /recipes/search?tag=X |
根据标签查询食谱 |
实现接口
添加一个新食谱
- POST /recipes
package main
import (
"net/http"
"strings"
"time"
"github.com/gin-gonic/gin"
"github.com/rs/xid"
)
type Recipe struct {
ID string `json:"id"`
Name string `json:"name"`
Tags []string `json:"tags"`
Ingredients []string `json:"ingredients"`
Instructions []string `json:"instructions"`
PublishedAt time.Time `json:"publishedAt"`
}
// 保存recipes数据
var recipes []Recipe
func init() {
recipes = make([]Recipe, 0)
}
func NewRecipeHandler(c *gin.Context) {
// POST /recipes。创建新食谱
var recipe Recipe
if err := c.ShouldBindJSON(&recipe); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
recipe.ID = xid.New().String()
recipe.PublishedAt = time.Now()
recipes = append(recipes, recipe)
c.JSON(http.StatusOK, recipe)
}
func main(){
router := gin.Default()
router.POST("/recipes", NewRecipeHandler)
router.Run("127.0.0.1:8080")
}
- 使用python进行测试
import requests
import json
def post_test(data):
url = "http://127.0.0.1:8080/recipes"
resp = requests.post(url=url, data=json.dumps(data))
print("post test")
print(resp.text)
if __name__ == "__main__":
data1 = {
"name": "Homemade Pizza",
"tags": ["italian", "pizza", "dinner"],
"ingredients": [
"1 1/2 cups (355 ml) warm water (105°F-115°F)",
"1 package (2 1/4 teaspoons) of active dry yeast",
"3 3/4 cups (490 g) bread flour",
"feta cheese, firm mozzarella cheese, grated",
],
"instructions": [
"Step 1.",
"Step 2.",
"Step 3.",
],
}
post_test(data1)
获取所有食谱
- GET /recipes
func ListRecipesHandler(c *gin.Context) {
c.JSON(http.StatusOK, recipes)
}
func main(){
router.GET("/recipes", ListRecipesHandler)
}
- python测试
def get_test():
url = "http://127.0.0.1:8080/recipes"
resp = requests.get(url)
print("get test")
print(resp.text)
get_test()
根据食谱id更新食谱
func UpdateRecipeHandler(c *gin.Context) {
// PUT /recipes/:id
id := c.Param("id")
var recipe Recipe
if err := c.ShouldBindJSON(&recipe); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
index := -1
// 根据id遍历查询
for i := 0; i < len(recipes); i++ {
if recipes[i].ID == id {
index = i
}
}
if index == -1 {
c.JSON(http.StatusNotFound, gin.H{
"error": "Recipe Not Found",
})
return
}
recipe.ID = id
recipes[index] = recipe
c.JSON(http.StatusOK, recipe)
}
func main(){
router.PUT("/recipes/:id", UpdateRecipeHandler)
}
- python测试
def put_test(data, id):
url = f"http://127.0.0.1:8080/recipes/{id}"
# data["id"] = id
resp = requests.put(url=url, data=json.dumps(data))
print("put test")
print(resp.text)
data2 = {
"name": "西红柿炒鸡蛋",
"tags": ["家常菜", "新手必会"],
"ingredients": [
"2个鸡蛋",
"1个番茄, 切片",
"葱花, 蒜瓣等",
],
"instructions": [
"步骤1",
"步骤2",
"步骤3",
],
}
put_test(data2, id="someidstring")
根据id删除食谱
func DeleteRecipeHandler(c *gin.Context) {
// DELETE /recipes/:id
id := c.Param("id")
index := -1
// 根据id遍历查询
for i := 0; i < len(recipes); i++ {
if recipes[i].ID == id {
index = i
}
}
if index == -1 {
c.JSON(http.StatusNotFound, gin.H{
"error": "Recipe Not Found",
})
return
}
// 通过切片切割实现删除元素
recipes = append(recipes[:index], recipes[index+1:]...)
c.JSON(http.StatusOK, gin.H{
"message": "Recipe has been deleted",
})
}
func main(){
router.DELETE("/recipes/:id", DeleteRecipeHandler)
}
- python测试
def delete_test(id):
url = f"http://127.0.0.1:8080/recipes/{id}"
resp = requests.delete(url=url)
print("delete test")
print(resp.text)
delete_test(id="someIdString")
根据标签搜索食谱
func SearchRecipeHandler(c *gin.Context) {
// GET /recipes/search
tag := c.Query("tag")
listOfRecipes := make([]Recipe, 0)
for i := 0; i < len(recipes); i++ {
found := false
for _, t := range recipes[i].Tags {
if strings.EqualFold(t, tag) {
found = true
}
}
if found {
listOfRecipes = append(listOfRecipes, recipes[i])
}
}
c.JSON(http.StatusOK, listOfRecipes)
}
func main(){
router.GET("/recipes/search", SearchRecipeHandler)
}
- python测试
def get_test_search(tag):
url = f"http://127.0.0.1:8080/recipes/search?tag={tag}"
resp = requests.get(url=url)
print("get test search")
print(resp.text)
get_test_search(tag="家常菜")
完整示例代码
package main
import (
"net/http"
"strings"
"time"
"github.com/gin-gonic/gin"
"github.com/rs/xid"
)
type Recipe struct {
ID string `json:"id"`
Name string `json:"name"`
Tags []string `json:"tags"`
Ingredients []string `json:"ingredients"`
Instructions []string `json:"instructions"`
PublishedAt time.Time `json:"publishedAt"`
}
// 保存recipes
var recipes []Recipe
func init() {
recipes = make([]Recipe, 0)
}
func NewRecipeHandler(c *gin.Context) {
// POST /recipes。创建新食谱
var recipe Recipe
if err := c.ShouldBindJSON(&recipe); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
recipe.ID = xid.New().String()
recipe.PublishedAt = time.Now()
recipes = append(recipes, recipe)
c.JSON(http.StatusOK, recipe)
}
func ListRecipesHandler(c *gin.Context) {
c.JSON(http.StatusOK, recipes)
}
func UpdateRecipeHandler(c *gin.Context) {
// PUT /recipes/:id
id := c.Param("id")
var recipe Recipe
if err := c.ShouldBindJSON(&recipe); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
index := -1
for i := 0; i < len(recipes); i++ {
if recipes[i].ID == id {
index = i
}
}
if index == -1 {
c.JSON(http.StatusNotFound, gin.H{
"error": "Recipe Not Found",
})
return
}
recipe.ID = id
recipes[index] = recipe
c.JSON(http.StatusOK, recipe)
}
func DeleteRecipeHandler(c *gin.Context) {
// DELETE /recipes/:id
id := c.Param("id")
index := -1
for i := 0; i < len(recipes); i++ {
if recipes[i].ID == id {
index = i
}
}
if index == -1 {
c.JSON(http.StatusNotFound, gin.H{
"error": "Recipe Not Found",
})
return
}
recipes = append(recipes[:index], recipes[index+1:]...)
c.JSON(http.StatusOK, gin.H{
"message": "Recipe has been deleted",
})
}
func SearchRecipeHandler(c *gin.Context) {
// GET /recipes/search
tag := c.Query("tag")
listOfRecipes := make([]Recipe, 0)
for i := 0; i < len(recipes); i++ {
found := false
for _, t := range recipes[i].Tags {
if strings.EqualFold(t, tag) {
found = true
}
}
if found {
listOfRecipes = append(listOfRecipes, recipes[i])
}
}
c.JSON(http.StatusOK, listOfRecipes)
}
func main() {
router := gin.Default()
router.POST("/recipes", NewRecipeHandler)
router.GET("/recipes", ListRecipesHandler)
router.PUT("/recipes/:id", UpdateRecipeHandler)
router.DELETE("/recipes/:id", DeleteRecipeHandler)
router.GET("/recipes/search", SearchRecipeHandler)
router.Run("127.0.0.1:8080")
}
本文来自博客园,作者:花酒锄作田,转载请注明原文链接:https://www.cnblogs.com/XY-Heruo/p/16413735.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· winform 绘制太阳,地球,月球 运作规律
· 上周热点回顾(3.3-3.9)