使用Go和Gin编写RESTFul API

news2024/12/23 0:34:41

使用Go和Gin开发RESTFul API

对应的代码仓库地址:gocode

本篇内容介绍如何使用Go和 Gin Web Framework来编写RESTFul API 服务的基础知识。如果你还对Go的基础操作不熟悉的话最好还是先看一下: 入门教程

Gin是一个Go语言的Web开发框架,它简化了构建Web应用的编码。在下面的介绍和代码中,我们将通过Gin来路由请求、处理请求数据和返回JSON响应。

设计API端点

这里我们根据官方给出的示例来进行,我们将建立一个API,它可以访问一家出售古董黑胶唱片的商店。因此,我们需要创建可以查询和增加唱片的端点(官网用 endpoint 来表达,其实就是我们平常的接口路由的概念),下面是教程中会创建的两个端点:

/albums

  • GET: 用来查询所有的专辑,返回的是JSON数据
  • POST: 发送JSON数据的请求来添加专辑

/albums/:id

  • GET: 用来获取指定ID的专辑

创建文件夹和代码

首先我们创建存放我们代码的文件夹,这里命名为 web-service-gin ,然后进入到该文件夹,执行 go mod init进行初始化:

go mod init example/web-service-gin

创建数据

下面我们来设计数据结构,教程中为了简单演示,因此将数据是存储到了内存中进行处理,通常情况下是要结合数据库来一起使用的。因此本教程的数据在每次服务的关闭和启动后数据会被重新初始化为内存中的数据。

下面,我们创建一个名为 main.go 的文件,然后进行编码:

package main

type album struct {
    ID     string  `json:"id"`
    Title  string  `json:"title"`
    Artist string  `json:"artis"`
    Price  float64 `json:"price"`
}

一个独立的程序(相对库来说)它始终位于main包中,然后我们定义了 album 结构体,这里需要注意的是json:"id"这样的表示当被序列化为JSON时的字段名为什么,上面显是将序列化后的字段统一为小写,如果没有它们,在返回的JSON和传递参数的JSON都需要将首字母大写。

下面我们来创建一些数据,大家可以直接粘贴下面的数据到你的结构提下面

var albums = []album{
    {ID: "1", Title: "Blue Train", Artist: "John Coltrane", Price: 56.99},
    {ID: "2", Title: "Jeru", Artist: "Gerry Mulligan", Price: 17.99},
    {ID: "3", Title: "Sarah Vaughan and Clifford Brown", Artist: "Sarah Vaughan", Price: 39.99},
}

编写处理代码

下面,我们将实现处理数据的代码。

编写返回所有数据项代码

当客户端对/albums发起GET请求时,我们要把所有的数据项以JSON的形式返回给客户端,实现这个我们需要关注下面两点:

  • 处理响应的逻辑
  • 映射请求路径的逻辑

接下来,我们在代码中增加一个方法,名为 getAlbums

func getAlbums(c *gin.Context) {
    c.IndentedJSON(http.StatusOK, albums)
}

在上面的代码中,我们首先创建了一个 getAlbums 方法,这里的方法名可以随意,然后将gin.Context作为参数。gin.Context是Gin最终要的部分,它携带了请求的详情、验证和序列化JSON等等。然后Context.IndentedJSON的作用是将数据序列化为JSON后作为响应,这个方法的第一个参数是请求的状态,这里我们复制为了请求成功的状态,也就是200,第二个参数就是我们要序列化返回给客户端的数据。

注意:我们可以使用Context.JSON来代替Context.IndentedJSON,两者的区别是Context.JSON会是序列化后的JSON更紧凑,Context.IndentedJSON是带缩进的格式化后的JSON。

下面我们再添加主方法,它的作用是将请求和对应的处理进行关联

func main() {
    router := gin.Default()
    router.GET("/albums", getAlbums)
    
    router.Run("localhost:8080")
}

上面的代码中我们首先使用Default方法初始化了路由,然后使用路由的GET方法将请求路径为/albums和处理方法getAlbums进行关联。最后使用Run函数启动了一个host为localhost端口为8080的http服务。

添加完上面的代码后我们需要添加对应的依赖库,需要在 package main 下加入下面代码后保存文件:

package main

import (
    "net/http"
    "github.com/gin-gonic/gin"
)

运行代码

在运行代码前我们首先获取我们需要的相关依赖,这里我们使用 go get 命令去添加,执行如下代码:

go get .

然后我们在 main.go 的目录下运行代码

go run .

一旦运行,现在就有一个HTTP服务在运行,我么可以向它发送请求,你可以在浏览器输入地址: http://localhost:8080/albums来访问数据,或者使用curl命令在终端中请求

curl http://localhost:8080/albums

请求到的数据如下:

[
    {
        "id": "1",
        "title": "Blue Train",
        "artis": "John Coltrane",
        "price": 56.99
    },
    {
        "id": "2",
        "title": "Jeru",
        "artis": "Gerry Mulligan",
        "price": 17.99
    },
    {
        "id": "3",
        "title": "Sarah Vaughan and Clifford Brown",
        "artis": "Sarah Vaughan",
        "price": 39.99
    }
]

编写添加新数据项代码

下面我们编写另外一个端点,当用户对/albums发起POST请求时,我们将接收到的JSON数据反序列化后添加到albums数据中,同样的,我们下面的代码关注两个点:

  • 向存在的列表添加新数据项的逻辑
  • 处理POST请求的逻辑代码

首先,我们在 main.go 文件中增加下面的方法:

func postAlbums(c *gin.Context) {
    var newAlbum album

    //使用BindJSON来绑定接收到的JSON数据到newAlbum
    if err := c.BindJSON(&newAlbum); err != nil {
        return
    }
    //添加新的albm到slice中
    albums = append(albums, newAlbum)
    c.IndentedJSON(http.StatusCreated, newAlbum)
}

上面的代码中使用Context.BindJSON来绑定请求体到newAlbum,然后将新的album添加到albums slice中,最后添加201状态码,并将新添加的内容返回给客户端。下面我们修改main方法中的代码

func main() {
    router := gin.Default()
    router.GET("/albums", getAlbums)
    router.POST("/albums", postAlbums)

    router.Run("localhost:8080")
}

运行代码

go run .

接下来我们测试一下,如果你使用的是 Linux/MacOS 直接使用 curl 命令发起请求:

curl http://localhost:8080/albums \
    --include \
    --header "Content-Type: application/json" \
    --request "POST" \
    --data '{"id": "4","title": "The Modern Sound of Betty Carter","artist": "Betty Carter","price": 49.99}'

如果是Windows的话使用Postman或其他的请求工具,发送如下的JSON数据

{
    "id": "4",
    "title": "The Modern Sound of Betty Carter",
    "artist": "Betty Carter",
    "price": 49.99
}

我这里用客户端请求工具请求的结果如下:

请求截图

然后再次访问GET请求发现新增成功,结果如下:

[
    {
        "id": "1",
        "title": "Blue Train",
        "artis": "John Coltrane",
        "price": 56.99
    },
    {
        "id": "2",
        "title": "Jeru",
        "artis": "Gerry Mulligan",
        "price": 17.99
    },
    {
        "id": "3",
        "title": "Sarah Vaughan and Clifford Brown",
        "artis": "Sarah Vaughan",
        "price": 39.99
    },
    {
        "id": "4",
        "title": "The Modern Sound of Betty Carter",
        "artis": "",
        "price": 49.99
    }
]

编写返回指定的数据项代码

当客户端发起一个 /albums/[id]这样的GET请求时,我们需要从albums中找到匹配的ID然后返回给客户端,下面我们来编写代码,我们在postAlbums方法下面增加getAlbumByID的方法,代码如下:

func getAlbumByID(c *gin.Context) {
    id := c.Param("id")

    //循环albums列表,然后找打匹配的数据项,如果没有找到返回Not Found状态和信息
        for _, a := range albums {
        if a.ID == id {
            c.IndentedJSON(http.StatusOK, a)
            return
        }
    }
    c.IndentedJSON(http.StatusNotFound, gin.H{"message":"album not found"})    
}

上面的代码中使用Context.Param方法来检索请求路径中的对应占位符的参数,然后通过循环albums数据对比ID来找出对应的album数据,如果没有找到则返回404状态码,然后我们再修改main函数中的代码

func main() {
    router := gin.Default()
    router.GET("/albums", getAlbums)
    router.GET("/albums/:id", getAlbumByID)
    router.POST("/albums", postAlbums)

    router.Run("localhost:8080")
}

运行代码

再次运行代码,这次在之前GET请求的基础上修改为 http://localhost:8080/albums/1 ,这表示我们想查询ID为1的album数据项,请求结果如下:

{
    "id": "1",
    "title": "Blue Train",
    "artis": "John Coltrane",
    "price": 56.99
}

完整代码

下面是本篇教程中的完整代码

package main

import (
	"net/http"
	"github.com/gin-gonic/gin"
)

type album struct {
    ID     string  `json:"id"`
    Title  string  `json:"title"`
    Artist string  `json:"artis"`
    Price  float64 `json:"price"`
}

var albums = []album{
    {ID: "1", Title: "Blue Train", Artist: "John Coltrane", Price: 56.99},
    {ID: "2", Title: "Jeru", Artist: "Gerry Mulligan", Price: 17.99},
    {ID: "3", Title: "Sarah Vaughan and Clifford Brown", Artist: "Sarah Vaughan", Price: 39.99},
}

func getAlbums(c *gin.Context) {
	c.IndentedJSON(http.StatusOK, albums)
}

func postAlbums(c *gin.Context) {
	var newAlbum album
	if err := c.BindJSON(&newAlbum); err != nil {
		return
	}
	albums = append(albums, newAlbum)
	c.IndentedJSON(http.StatusCreated, newAlbum)
}

func getAlbumByID(c *gin.Context) {
	id := c.Param("id")

	for _, a := range albums {
		if a.ID == id {
			c.IndentedJSON(http.StatusOK, a)
			return
		}
	}
	c.IndentedJSON(http.StatusNotFound, gin.H{"message": "album not fond"})
}

func main() {
	router := gin.Default()
	router.GET("/albums", getAlbums)
	router.POST("/albums", postAlbums)
	router.GET("/albums/:id", getAlbumByID)

	router.Run("localhost:8080")
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/622993.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何实现企业微信扫码登录?

开发内容:实现网页企业微信扫码登录 企业微信提供了OAuth的授权登录方式,可以让从企业微信终端打开的网页获取成员的身份信息,从而免去登录的环节。 企业应用中的URL链接(包括自定义菜单或者消息中的链接)&#xff0c…

新手git使用记录

文章目录 前言一、下载安装git二、使用git1.基本概念2.git初始化设置3.基本操作3.1、拉取远程仓库代码,修改后在提交3.2、新建分支,提交 总结 前言 几年前在学校还学了git怎么使用,毕业后公司用tfs,这东西真的拉,感觉…

将Apple Vision Pro和visionOS与计算机视觉结合使用

在2023年6月5日的WWDC大会上,苹果宣布推出多年来最大规模的硬件和软件组合产品。今年的“One more thing”(“还有一件事”)发布是苹果视觉专业版(Apple Vision Pro),这是一款集成了苹果生态系统的新型空间…

mybatis多数据源的SQL兼容

背景 最近公司要求支持国产数据库达梦,但达梦与PostgreSQL的语法有一些差异,需要做一些兼容操作。 操作步骤 本文采用dynamic-datasource-spring-boot-starter框架处理多数据源,多数据源配置如下spring:datasource:dynamic:primary: dm #设…

华为OD机试真题B卷 Java 实现【进制转换】,附详细解题思路

一、题目描述 写出一个程序,接受一个十六进制的数,输出该数值的十进制表示。 二、输入描述 输入一个十六进制的数值字符串。 三、输出描述 输出该数值的十进制字符串。不同组的测试用例用\n隔开。 四、解题思路 读取输入的十六进制数值字符串&…

Selenium Python教程第2章

2. Selenium 编程入门 2.1 简单用例 如果你已经安装好了selenium,你可以把下面的python代码拷贝到你的编辑器中 from selenium import webdriver from selenium.webdriver.common.keys import Keysdriver webdriver.Firefox() driver.get("http://www.pytho…

AUTOSAR DoIP介绍

DoIP是什么 DoIP全称是Diagnostic Over IP,顾名思义就是基于IP的诊断,即下图所关联的ISO13400规范,也就是说如果大家想了解DoIP可以详细阅读ISO13400。 根据下图(来自于ISO14229-1),我们可以得到以下两点关系: UDS协议(规范是ISO14229)是统一诊断服务,作为应用层协议…

浏览器相关前端开发事项

文章目录 存储浏览器持久化存储(F12->应用->存储)浏览器缓存(F12->内存)浏览器存储管理单位(域名/IP为单位)区别localStorage VS 浏览器缓存localStorage VS cookies 存储 浏览器持久化存储&…

机器视觉陶瓷板表面划痕丝印检测方法

随着陶瓷制品在建筑、电子、医疗等领域的应用越来越广泛,对陶瓷制品的质量要求也越来越高。而陶瓷制品表面的划痕和丝印等缺陷会降低产品的美观度和质量,甚至会影响产品的安全性和使用寿命。传统的陶瓷板检测方式主要依赖人工目视检测,效率低…

FL Stuido21中文版水果编曲软件下载

FL stuido水果编曲软件做舞曲以及电子乐的利器,即便是在IPAD或者电脑端上操作,都非常的简便。界面逻辑非常友好,做rnb也是很可以的东西。可以作半成品的内容,声音采样方面还行,同样需要接口卡支持。钢琴卷帘操作还算便…

华为OD机试真题 Java 实现【字符串序列判定】【2022Q4 100分】,附详细解题思路

一、题目描述 输入两个字符串a和b&#xff0c;都只包含英文小写字母。a长度<100&#xff0c;b长度<500,000。 判定a是否是b的有效子串。 判定规则&#xff1a; a中的每个字符在b中都能找到&#xff08;可以不连续&#xff09;&#xff0c;且a在b中字符的前后顺序与a中…

FTL潜规则:调优,才是算法精华

前言 在存储领域中有一个FTL的概念&#xff0c;这是一种Flash的内存管理算法&#xff0c;属于各个厂商的核心机密&#xff0c;每个厂商的处理方式不同&#xff0c;有的处理简单&#xff0c;有的处理复杂。 FTL&#xff0c;即Flash Translations layer&#xff0c;也就是闪存转…

wayland浅析之EGL、Opengles、GBM

本文针对不同的compositor&#xff0c;浅析eglopenglesgbm搭配使用情况&#xff1b; 文章目录 1. 前言1.1 问题一&#xff1a;是不是调用eglSwapBuffers函数以后图像就直接显示到屏幕上了&#xff1f;1.2 问题二&#xff1a;EGL基本使用流程&#xff0c;EGL搭配GBM上屏显示基本…

JavaSE06_面向对象之封装

JavaSE-06 [面向对象OOP 封装] 第一章 面向对象思想 1.1 面向过程和面向对象 面向过程&#xff1a; 面向过程就是分析出解决问题所需要的步骤&#xff0c;然后用函数把这些步骤一步一步实现&#xff0c;使用的时候一个一个依次调用就可以了面向对象&#xff1a; 面向对象是…

Servlet、JSP

一、web服务器 1.1 常用服务器产品 Tomcat&#xff08;Apache开源&#xff0c;主流的web服务器之一&#xff0c;多用于javaweb项目开发&#xff09; jetty&#xff08;效率高于Tomcat&#xff09; WebLogic&#xff08;Oracl 收费&#xff09; WebSpera&#xff08;IBM&#xf…

cesium学习之旅1:cesium 基本介绍以及 cesium 的 hello world 程序

一&#xff1a;什么是Cesium Cesium 是一个跨平台、跨浏览器的展示三维地球和地图的 javascript 库。Cesium 使用WebGL 来进行硬件加速图形&#xff0c;使用时不需要任何插件支持&#xff0c;但是浏览器必须支持WebGL。Cesium是基于Apache2.0 许可的开源程序。它可以免费的用于…

代码随想录二刷 day16 | 二叉树之104.二叉树的最大深度 559.n叉树的最大深度 111.二叉树的最小深度 222.完全二叉树的节点个数

day16 104.二叉树的最大深度559.n叉树的最大深度111.二叉树的最小深度222.完全二叉树的节点个数 104.二叉树的最大深度 题目链接 解题思路&#xff1a;本题中根节点的高度就是最大深度 二叉树节点的深度&#xff1a; 指从根节点到该节点的最长简单路径边的条数或者节点数&…

TensorFlow项目练手——天气预测

项目介绍 通过以往的天气数据和实际天气温度&#xff0c;做一次回归预测&#xff0c;模型的输入是当前的所有特征值&#xff0c;而模型的输出是当天的实际天气温度 字段分析 目前已有的数据有348条svc数据&#xff0c;他们的字段分别代表 year&#xff1a;年month&#xff…

美客多卖家攻略:养号技巧分享

在跨境电商平台上成功运营并建立起具有竞争力的店铺并不容易。美客多作为一个颇具影响力的平台&#xff0c;更需要卖家们仔细研究和精心运营。在这里&#xff0c;我将分享一些秘诀&#xff0c;这些秘诀是在我自养号过程中总结出来的&#xff0c;有助于增加销量并提升店铺的排名…

高级数据分析师岗位的职责描述

高级数据分析师岗位的职责描述1 职责&#xff1a; 1.搭建和完善数据中心的数据指标体系与监控预测体系&#xff0c;并推动系统化实现; 2.负责对市场、行业、竞争对手、产品、客户、业务运营等方面数据的收集、分析&#xff0c;完成整理出分析报告、提供数据支持、分析建议; 3.对…