现在开发API,所输出的基本上都是JSON格式的内容,相比比较旧的XML格式,JSON轻便、简洁、易于传输,所以现在的API使用非常多。
Gin对于API JSON的支持非常友好,可以让我们非常方便的开发一个基于JSON的API。
1 2 3 4 5 6 7 | func main() { r := gin.Default() r.GET("/hello", func(c *gin.Context) { c.JSON(200, gin.H{"message": "hello world"}) }) r.Run(":8080") } |
---|
一个非常简单的例子,主要知识点在于c.JSON
方法,它可以让我们非常方便的输出JSON格式的内容。
现在运行打开浏览器访问http://localhost:8080/hello
可以看到如下内容:
{"message":"hello world"}
这是一个JSON格式的字符串,第三方调用者可以获得这个JSON内容,把它转换为一个JSON对象,然后通过message
字段获取对应的值,也就是hello world
。
这里我们使用了gin.H
这个类型来构建了一个键值对对象,其实gin.H
是一个map[string]interface{}
。
1 2 | // H is a shortcut for mapstringinterface{} type H mapstringinterface{} |
---|
gin.H
主要是为了帮助我们开发者很方便的构建出一个map
对象,不止用于c.JSON
方法,也可以用于其他场景。
c.JSON
方法非常强大,不止可以用于map
的输出,还可以把我们自定义的对象struct
转为一个json字符串输出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | func main() { r := gin.Default() r.GET("/users/123", func(c *gin.Context) { c.JSON(200, user{ID: 123, Name: "张三", Age: 20}) }) r.Run(":8080") } type user struct { ID int Name string Age int } |
---|
这个例子中我们自定义了一个user
struct 来表示用户,然后我们注册一个用户ID为123的路由,用于输出这个用户的信息,这里使用的就是user
struct,把它作为参数直接传给c.JSON
方法即可。
现在我们运行,在浏览器里访问http://localhost:8080/users/123
可以看到如下信息:
{"ID":123,"Name":"张三","Age":20}
完美、简单的把这个用户的信息作为一个JSON字符串输出。
看上面的例子,我们发现输出的JSON字符串的字段和我们定义的user
的字段名一样,但是这样的命名格式显然不太适合JSON,因为JSON的字段应该是小写字母开头的,这比较符合当前大家所遵守的JSON风格。
Gin是支持字段名字重新命名的,并且很简单,和Golang原生的JSON一样。
1 2 3 4 5 | type user struct {
ID int |
---|
只需要在user
struct 定义的时候为字段添加json tag
即可。关于 Struct Tag 的内容请参考我以前写的 Go语言实战笔记(二十五)| Go Struct Tag 这篇文章,这里不再赘述。
现在我们重新运行,在浏览器里访问http://localhost:8080/users/123
,发现看到的信息已经变了:
{"id":123,"name":"张三","age":20}
更符合JSON的风格了,看着更顺眼一些。
在一些情况下,比如我们需要获取所有用户信息,那么表达为JSON字符串来说,就是一个JSON数组。在Gin中,生成JSON数组也很简单,只要我们传递给c.JSON
的参数是个数组就可以。
1 2 3 4 | allUsers := []user{{ID: 123, Name: "张三", Age: 20}, {ID: 456, Name: "李四", Age: 25}} r.GET("/users", func(c *gin.Context) { c.IndentedJSON(200, allUsers) }) |
---|
我们首先定义了一个user
数组,然后使用c.IndentedJSON
输出JSON字符串,现在运行打开浏览器,访问http://localhost:8080/users
就可以看到如下信息,一个JSON数组字符串:
[
{
"id": 123,
"name": "张三",
"age": 20
},
{
"id": 456,
"name": "李四",
"age": 25
}
]
上面的例子,我们可以看到,输出的JSON字符串都是扁平的,没有缩进,不美观。对于这种情况,Gin也为我们提供了便捷的方法,让我们输出的JSON更好看。
1 2 3 | r.GET("/users/456", func(c *gin.Context) { c.IndentedJSON(200, user{ID: 456, Name: "李四", Age: 25}) }) |
---|
想美化JSON的输出,使用c.IndentedJSON
方法即可,现在现在我们运行访问http://localhost:8080/users/456
就可以看到JSON已经被美化了,更容易看了。。
{
"id": 456,
"name": "李四",
"age": 25
}
对于JSON字符串中特殊的字符串,比如<
,Gin默认是转义的,比如变成\ u003c
,但是有时候我们为了可读性,需要保持原来的字符,不进行转义,这时候我们就可以使用PureJSON
1 2 3 4 5 6 7 8 9 10 11 12 | r.GET("/json", func(c *gin.Context) { c.JSON(200, gin.H{ "message": "<b>Hello, world!</b>", }) }) r.GET("/pureJson", func(c *gin.Context) { c.PureJSON(200, gin.H{ "message": "<b>Hello, world!</b>", }) }) |
---|
用这两个API进行对比,我们运行访问http://localhost:8080/json
,显示信息如下:
{"message":"\u003cb\u003eHello, world!\u003c/b\u003e"}
特殊字符已经被转义了,现在访问http://localhost:8080/pureJson
,显示的就是原始信息:
{"message":"<b>Hello, world!</b>"}
可读性更强。
如果要把非Ascii
字符串转为unicode编码,Gin同样提供了非常方便的方法。
1 2 3 | r.GET("/asciiJSON", func(c *gin.Context) { c.AsciiJSON(200, gin.H{"message": "hello 飞雪无情"}) }) |
---|
通过c.AsciiJSON
方法,Gin可以把所有的非Ascii
字符全部转义为unicode
编码,现在我们运行看看结果。
{"message":"hello \u98de\u96ea\u65e0\u60c5"}
飞雪无情
4个字已经被转义为\u98de\u96ea\u65e0\u60c5
了,避免乱码。
在Gin中,提供了两种JSON解析器,用于生成JSON字符串。默认的是Golang(Go语言)内置的JSON,当然你也可以使用jsoniter,据说速度很快。如果要使用jsoniter,我们在go build
编译的时候只需要这么做即可:
go build -tags=jsoniter .
这样我们就是用了jsoniter,是基于条件编译的技术,具体可以参考我这篇文章 Go语言中自动选择json解析库 。
Golang Gin 实战(六)| 获取Form表单参数和原理分析
Golang Gin 实战(四)| URL查询参数的获取和原理分析
Golang Gin 实战(二)| 简便的Restful API 实现