前言

代码参考自《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")
}

[gin]基于切片实现crud的更多相关文章

  1. 基于mybatis的CRUD

    u  基于Mybatis的CRUD u  掌握MyBatis的结果类型-resultMap和resultType u  掌握MyBatis的参数类型 u  掌握#和$两种语法 1      基于myb ...

  2. SpringMVC 学习笔记(五) 基于RESTful的CRUD

    1.1. 概述 当提交的表单带有_method字段时,通过HiddenHttpMethodFilter 将 POST 请求转换成 DELETE.PUT请求,加上@PathVariable注解从而实现  ...

  3. Mybatis基于SqlSession实现CRUD

    之前我们讲的基于XML还是接口注解配置都是使用接口实现CRUD,本文我们将要讲解通过splsession来实现CRUD,这种方法比较灵活. 基本配置 <!-- spring和MyBatis完美整 ...

  4. [深度学习] 基于切片辅助超推理库SAHI优化小目标识别

    对象检测是迄今为止计算机视觉中最重要的应用领域.然而,小物体的检测和大图像的推理仍然是实际使用中的主要问题,这是因为小目标物体有效特征少,覆盖范围少.小目标物体的定义通常有两种方式.一种是绝对尺度定义 ...

  5. MVC基于Struts2的CRUD,java+bean+struts

    1,所需jar包,将jar包导入lib中 2,项目目录结构 3,struts.xml <?xml version="1.0" encoding="UTF-8&quo ...

  6. 基于SSM的CRUD项目的详解

    创一个maven工程 创建web的目录和web.xml------------右击项目,build projet--->configure  project---->Project fac ...

  7. 基于SSM之Mybatis接口实现增删改查(CRUD)功能

    国庆已过,要安心的学习了. SSM框架以前做过基本的了解,相比于ssh它更为优秀. 现基于JAVA应用程序用Mybatis接口简单的实现CRUD功能: 基本结构: (PS:其实这个就是用的Mapper ...

  8. 一步步学Mybatis-实现单表情况下的CRUD操作 (3)

    今天这一章要紧接上一讲中的东西,本章中创建基于单表操作的CRUD与GetList操作,此示例中以Visitor表为范例,为了创建一点测试数据我们先弄个Add方法吧 继续在上次的IVisitorOper ...

  9. 第四章 go语言 数组、切片和映射

    文章由作者马志国在博客园的原创,若转载请于明显处标记出处:http://www.cnblogs.com/mazg/ 数组是由同构的元素组成.结构体是由异构的元素组成.数据和结构体都是有固定内存大小的数 ...

  10. Go语言类型(布尔、整型、数组、切片、map等)

    1.基本类型 布尔类型:bool 注意:布尔类型不能接受其他类型的赋值,不支持自动或强制的类型转换. 整型:int8.byte(uint8).int16.int.uint.uintptr int.ui ...

随机推荐

  1. 【Visual C#】基于《斗鱼弹幕服务器第三方接入协议v1.6.2》实现斗鱼弹幕服务器接入

    最近在给某个主播开发斗鱼直播间辅助工具,为了程序的高效稳定,也搜索了大量的资料,经过大量什么百度,谷歌搜索... 虽然有很多Python的脚本及JS脚本实现了拉取斗鱼弹幕信息,但是这些年来的开发职业病 ...

  2. 2021-04-22:给定很多线段,每个线段都有两个数[start, end],表示线段开始位置和结束位置,左右都是闭区间,规定:1)线段的开始和结束位置一定都是整数值,2)线段重合区域的长度必须>=

    2021-04-22:给定很多线段,每个线段都有两个数[start, end],表示线段开始位置和结束位置,左右都是闭区间,规定:1)线段的开始和结束位置一定都是整数值,2)线段重合区域的长度必须&g ...

  3. Flutter编写的数独游戏

    一个使用Flutter编写的每日数独小游戏,支持Android和ios.代码已上传到github:https://github.com/huhx/flutter_sudoku Library 状态管理 ...

  4. 深入理解 python 虚拟机:魔术方法之数学计算

    深入理解 python 虚拟机:魔术方法之数学计算 在本篇文章当中主要给大家介绍在 python 当中一些常见的魔术方法,本篇文章主要是关于与数学计算相关的一些魔术方法,在很多科学计算的包当中都使用到 ...

  5. Springboot 开启异步任务Async,邮件发送任务,定时任务

    异步任务 1.主启动类开启异步注解 2.service目录下开启异步任务注解 @Service public class AsyncService { @Async//异步任务注解的标志 public ...

  6. Python 列表、字典、元组的一些小技巧

    1. 字典排序 我们知道 Python 的内置 dictionary 数据类型是无序的,通过 key 来获取对应的 value.可是有时我们需要对 dictionary 中的 item 进行排序输出, ...

  7. 使用 conda 和 Jupyter 创建你的自定义 R 包,转换笔记为幻灯片

    创建你的自定义 R 包 出于用户使用方便考虑,Anaconda 已经在 "R Essentials" 中打包了一些最常用的数据科学 R 包.使用 conda metapackage ...

  8. BGP 反射器;BGP联盟

    目录 BGP反射器 实验拓扑 实验需求 实验步骤 在R2上查看BGP邻居表 在R2上做反射器 在R3上查看1.1.1.1 路由表,进行观察 在R3上查看1.1.1.1 路由详细信息 BGP联盟实验 实 ...

  9. 【2023 · CANN训练营第一季】昇腾AI入门Pytorch

    昇腾AI全栈架构 华为AI全栈全场景解决方案为4层,分别为芯片层.芯片使能层.AI框架层和应用使能层. 芯片 基于统一.可扩展架构的系列化AI IP和芯片,为上层加速提供硬件基础. 芯片产品:昇腾31 ...

  10. TLS详解(原理和实践)

    主页 个人微信公众号:密码应用技术实战 个人博客园首页:https://www.cnblogs.com/informatics/ 引言 本文主要内容涉及到TLS协议发展历程.TLS协议原理以及在HTT ...