[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")
}
[gin]基于切片实现crud的更多相关文章
- 基于mybatis的CRUD
u 基于Mybatis的CRUD u 掌握MyBatis的结果类型-resultMap和resultType u 掌握MyBatis的参数类型 u 掌握#和$两种语法 1 基于myb ...
- SpringMVC 学习笔记(五) 基于RESTful的CRUD
1.1. 概述 当提交的表单带有_method字段时,通过HiddenHttpMethodFilter 将 POST 请求转换成 DELETE.PUT请求,加上@PathVariable注解从而实现 ...
- Mybatis基于SqlSession实现CRUD
之前我们讲的基于XML还是接口注解配置都是使用接口实现CRUD,本文我们将要讲解通过splsession来实现CRUD,这种方法比较灵活. 基本配置 <!-- spring和MyBatis完美整 ...
- [深度学习] 基于切片辅助超推理库SAHI优化小目标识别
对象检测是迄今为止计算机视觉中最重要的应用领域.然而,小物体的检测和大图像的推理仍然是实际使用中的主要问题,这是因为小目标物体有效特征少,覆盖范围少.小目标物体的定义通常有两种方式.一种是绝对尺度定义 ...
- MVC基于Struts2的CRUD,java+bean+struts
1,所需jar包,将jar包导入lib中 2,项目目录结构 3,struts.xml <?xml version="1.0" encoding="UTF-8&quo ...
- 基于SSM的CRUD项目的详解
创一个maven工程 创建web的目录和web.xml------------右击项目,build projet--->configure project---->Project fac ...
- 基于SSM之Mybatis接口实现增删改查(CRUD)功能
国庆已过,要安心的学习了. SSM框架以前做过基本的了解,相比于ssh它更为优秀. 现基于JAVA应用程序用Mybatis接口简单的实现CRUD功能: 基本结构: (PS:其实这个就是用的Mapper ...
- 一步步学Mybatis-实现单表情况下的CRUD操作 (3)
今天这一章要紧接上一讲中的东西,本章中创建基于单表操作的CRUD与GetList操作,此示例中以Visitor表为范例,为了创建一点测试数据我们先弄个Add方法吧 继续在上次的IVisitorOper ...
- 第四章 go语言 数组、切片和映射
文章由作者马志国在博客园的原创,若转载请于明显处标记出处:http://www.cnblogs.com/mazg/ 数组是由同构的元素组成.结构体是由异构的元素组成.数据和结构体都是有固定内存大小的数 ...
- Go语言类型(布尔、整型、数组、切片、map等)
1.基本类型 布尔类型:bool 注意:布尔类型不能接受其他类型的赋值,不支持自动或强制的类型转换. 整型:int8.byte(uint8).int16.int.uint.uintptr int.ui ...
随机推荐
- 2023-02-22:请用go语言调用ffmpeg,保存mp4文件的视频帧,每帧用ppm图片保存。
2023-02-22:请用go语言调用ffmpeg,保存mp4文件的视频帧,每帧用ppm图片保存. 答案2023-02-22: 使用 github.com/moonfdd/ffmpeg-go 库. 先 ...
- 2022-09-24:以下go语言代码输出什么?A:1;B:3;C:13;D:7。 package main import ( “fmt“ “io/ioutil“ “net/
2022-09-24:以下go语言代码输出什么?A:1:B:3:C:13:D:7. package main import ( "fmt" "io/ioutil" ...
- 2021-01-03:java中,描述一下什么情况下,对象会从年轻代进入老年代?
福哥答案2021-01-03: 1.对象的年龄超过一定阀值,-XX:MaxTenuringThreshold 可以指定该阀值.2.动态对象年龄判定,有的垃圾回收算法,比如 G1,并不要求 age 必须 ...
- 2022-04-21:给定一个包含 [0,n) 中不重复整数的黑名单 blacklist, 写一个函数从 [0, n) 中返回一个不在 blacklist 中的随机整数, 对它进行优化使其尽量少调用系
2022-04-21:给定一个包含 [0,n) 中不重复整数的黑名单 blacklist, 写一个函数从 [0, n) 中返回一个不在 blacklist 中的随机整数, 对它进行优化使其尽量少调用系 ...
- Django4全栈进阶之路15 项目实战(用户管理):login.html登录画面设计
要编写登录页面,我们需要完成以下步骤: template文件夹中创建 login.html 模板文件,输入以下 HTML 代码: {% extends 'base.html' %} {% block ...
- docker容器使用(1)
docker容器使用(1) 几个简单的参数 查看全部的容器 docker ps -a -d 以分离模式运行/在后台运行 -i以交互模式运行 -t在终端运行 -p --publish 端口映射-p表示把 ...
- Blazor实战——Known框架增删改查导
本章介绍学习增.删.改.查.导功能如何实现,下面以商品资料作为示例,该业务栏位如下: 类型.编码.名称.规格.单位.库存下限.库存上限.备注 1. 前后端共用 1.1. 创建实体类 在KIMS项目En ...
- Pycharm激活码,Pycharm稳定专属激活码(持续更新)
分享一下 PyCharm 2023.1.2 最新激活注册码,破解教程如下,可免费永久激活,亲测有效,下面是详细文档哦~ 申明:本教程 PyCharm 激活码收集于网络,请勿商用,仅供个人学习使用,如有 ...
- 微生物组分析软件 QIIME 2 安装小记
由于微信不允许外部链接,你需要点击文章尾部左下角的 "阅读原文",才能访问文中链接. QIIME 2 是一个功能强大,可扩展,分散式的(decentralized)微生物组分析软件 ...
- VLAN——提高网络性能、安全性和灵活性的利器
前言 VLAN是Virtual Local Area Network的缩写,它是一种通过网络交换机虚拟划分局域网的技术.VLAN可以将一个物理局域网划分成多个逻辑上的虚拟局域网,各个虚拟局域网之间相互 ...