[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 ...
随机推荐
- dede网站flash中图片不能正常显示解决办法
专业微信开发 网站制作 就在西安格创网络 联系电话:18009249661 原因:因为服务器或虚拟主机用了CDN加速,导致图片是调用远程缓存,只能显示FLASH控件,但图片不能正常显示,常见于西 ...
- MAUI开发Android程序使PDA扫码广播消息转发至Web页面
前言 公司系统的手持终端(PDA)是用的Vue写的前端代码 在PDA上用浏览器直接打开Web页面 PDA扫码的时候,输出模式直接用模拟键盘按键的方式输出 这样在Web页面上,如果一个输入框在当前有焦点 ...
- 2022-05-05:给定一个正数num,要返回一个大于num的数,并且每一位和相邻位的数字不能相等. 返回达标的数字中,最小的那个。 来自微软。
2022-05-05:给定一个正数num,要返回一个大于num的数,并且每一位和相邻位的数字不能相等. 返回达标的数字中,最小的那个. 来自微软. 答案2022-05-05: 从左往右看,是否有相邻两 ...
- 2022-01-03:比如arr = {3,1,2,4}, 下标对应是:0 1 2 3, 你最开始选择一个下标进行操作,一旦最开始确定了是哪个下标,以后都只能在这个下标上进行操作。 比如你选定1下标,
2022-01-03:比如arr = {3,1,2,4}, 下标对应是:0 1 2 3, 你最开始选择一个下标进行操作,一旦最开始确定了是哪个下标,以后都只能在这个下标上进行操作. 比如你选定1下标, ...
- ArcGIS如何自动获得随机采样点?
本文介绍基于ArcMap软件,实现在指定区域自动生成随机点的方法. 在GIS应用中,我们时常需要在研究区域内进行地理数据的随机采样:而采样点的位置往往需要在结合实际情况的前提下,用计算机随机生 ...
- 用token辅助 密码爆破
第一步:打开皮卡丘,点击暴力破解,token防爆破,输入正确用户名,错误密码 BP拦截请求,点击皮卡丘Login,然后拦截后, 发送给Intruder 第二步: 爆破方式选择音叉方式, & ...
- js 之二 事件对象
事件对象 /当事件的响应函数被触发时,浏览器每次都会讲一个事件对象作为实参传递响应函数; 在事件对象中封装了当前事件相关的一切信息,比如:鼠标的,键盘的操作 // 当鼠标在areaDiv中移动时,在s ...
- 信息收集_网络扫描_nmap
信息收集_网络扫描nmap 目标说明 -iL <inputname> (从列表或文件输入) -iR <hostnum> (随机选择生成目标数量) --exclude <h ...
- VLAN——提高网络性能、安全性和灵活性的利器
前言 VLAN是Virtual Local Area Network的缩写,它是一种通过网络交换机虚拟划分局域网的技术.VLAN可以将一个物理局域网划分成多个逻辑上的虚拟局域网,各个虚拟局域网之间相互 ...
- x.ai还是OpenAI?埃隆·马斯克的AI帝国【1】
大家可能知道,在上个月底埃隆·马斯克与1000多名来自各个行业的专家一起联名签署了"Future of Life Institute"发起的一个请愿书,呼吁全社会暂停至少6个月的高 ...