写在开头
非原创,仅用于自身学习系统设计
文集目录
1.API风格
目前业界常用的API风格有三种:
- REST
- RPC
- Graphql
其中restful api使用的是http协议,rpc api使用rpc协议,rpc api因为性能高调用方便,更适合在业务内部,而restful api因为规范,通俗易懂,更适合对外提供接口。出于学习swagger的目的,我们也是接下来着重讲解restfull api和其规范
1.1Rest规范
rest有一系列规范,满足这些规范的api均可称为restful api。
规范特点:
- Rest规范把所有都看作资源。由于对资源的操作(获取、创建、更新等)正好对应HTTP协议提供的方法(GET/POST/PUT),因此REST天生和HTTP协议相辅相成。对于HTTP来说,资源使用URI标识,如root用户,那么该资源的URI标识就可以是/user/root
- 资源是有状态的,使用JSON/XML等在http包体标识资源状态
- 无状态,即每个restful api请求都包含了所有足够完成本次操作的信息,服务的无需保持session
1.2Restful api设计原则
1.2.1URI设计
资源使用URI标识,所以我们尽量遵循以下规范保证该标识能让我们的接口更易读:
- 资源名使用名词而不是动词,并且用复数表示。资源分为集合和成员,集合就是一堆资源的集合,如系统中的全部用户,这些用户的集合的URI标识应该是 域名/资源名复数,如http://xxx.com/users;反之成员就是单个,它的标识应该是域名/资源复数名/资源名,如http://xxx.com/users/root
- URI结尾不应该包含斜杠/
- URI中不能出现下划线,必须用中杠线代替(这条还是因人而异,如谷歌业务中URI不能出现下划线)
- URI路径用小写,不用大写
- 避免过深的URI,超过2层的资源嵌套很乱。
当遇到过深的嵌套时或不好映射成REST资源时,可以使用以下办法:
- 将其他资源转为?参数
不推荐
/users//name/root/age/11
推荐
/users/root?age=11
- 将操作变成一个资源的属性
active对应user的一个属性
/users/root?active=false
3.将操作当成是一个资源或者资源的嵌套,如登录和收藏
登录
/login
收藏
/gists/:id/star
1.2.2HTTP方法
就是对应的CURD,没啥好提的,直接偷图需要注意批量删除的需求,但是delete方法不能携带多个请求名,这时可以采用以下办法:
- 发起多个delete请求
- 路径中带多个id,id用分隔符分隔
delete /users?id=1,2,3
- 直接使用post请求,在包体中传入多个id
1.2.3统一返回格式
即当向外界开放多个资源接口,每个接口返回格式统一,返回成功和失败的两种消息格式也要保持统一
1.2.4 版本管理
当出现一个API无法向下兼容,通常引入API版本机制,我们通常将版本标识放在3个位置:
- URI 如 /v1/users
- HTTP头
- Form参数 /users?version=v1
1.2.5统一分页/过滤/搜索功能
- 分页:在列出用户表时,为减少API响应延时,避免返回太多,应提供分页功能,如/users?page=0&limit=20
- 过滤:如果用户不需要一个资源的全部属性,可以在URI参数里指定返回属性 /users?field=name,age
- 排序:同上在URI中指出 /users?sort=age
- 搜索:同上 /user?name=root
1.2.6域名
- xxx.com/api 适合未来不会有扩展的情况,即xxx.com域名只有一套API系统,未来也只有一套
- xxx.api.xxx.com 适用于 xxx.com域名下会新增另一个系统API,这时每个系统有专有的API域名,腾讯云就是采用该方法
2.Swagger
Swagger是一套围绕OpenAPI规范构建的开源工具,可以设计、构建、编写和使用Restful API。
openapi是一个api规范,swagger是实现规范的工具,openapi规范规定了一个API必须包含如下基本信息:1.对API功能实现的描述;2.每个API上可用的路径和操作;3.每个API的输入、返回函数;4.验证方法;5.联系信息等
更直接点讲就是swagger就是帮我们写API接口文档的工具。
在GO项目中,可以通过以下办法生成swagger
api文档:
- 直接使用yaml或json手撸,不推荐,工作量大
- 使用swag和go-swagger两个工具生成,前者需要为每一个API写一个超长的注释,有时比代码更长,后者能将代码和注释分开编写,所以我个人更推荐后者
2.1go-swagger
go-swagger使用的是open api2.0的规范,因此在使用前,请确保你已经了解,如果您未学习swagger,请点击下方进行前置学习
- openapi2.0: 请点击此处查看并学习openapi2.0语法
- swagger-editor: 同时点击此处使用openapi 2.0规范,在线手撸swagger api文档
- 安装go-swagger
github项目地址
因为我的go版本是1.20的,所以不安装最新的,1.22以上的可以直接选择last版本
go install github.com/go-swagger/go-swagger/cmd/swagger@v0.30.0
之后建议将下面三个教程看一下,选择其中一个跟着敲一下
官网的初级教程如下
2.2 写一个最简单的例子
实验源码在此
项目文件名
/swagger
/swagger/internal/usersrv/user.go 提供了用户信息查询服务,我们需要对该接口编写swagger文档
func UserHanler(ctx *gin.Context) {
ctx.JSON(http.StatusOK, gin.H{
"Code": 1000,
"Data": gin.H{
"user": gin.H{
"name": "root",
},
},
})
}
服务启动文件main.go位于 /swagger/cmd/usersrv/main.go,注意本地测试设置跨域
func main() {
srv := gin.Default()
srv.Use(func(c *gin.Context) {
method := c.Request.Method
origin := c.Request.Header.Get("Origin")
if origin != "" {
c.Header("Access-Control-Allow-Origin", "*") // 可将将 * 替换为指定的域名
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
c.Header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization")
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Cache-Control, Content-Language, Content-Type")
c.Header("Access-Control-Allow-Credentials", "true")
}
if method == "OPTIONS" {
c.AbortWithStatus(http.StatusNoContent)
}
c.Next()
})
srv.GET("/v1/users/:User", usersrv.UserHanler)
srv.Run(":8088")
}
我们利用go文件生成swagger文档,保存于 /swagger/docs下
docs.go用于记录初始信息
// Package docs usersrv
//
// usersrv API文档.
//
// Schemes: http, https
// BasePath: /v1
// Version: 1.0.0
// Host: localhost:8088
//
//
// Consumes:
// - application/json
// - application/xml
//
// Produces:
// - application/json
// - application/xml
//
// swagger:meta
package doc
需要严格注意大小写,一行写错了就不会记录进yaml文件中
- package docs后面跟服务名称usersrv,等价于openAPI2.0的
info:
title: usersrv
- 之后跟服务介绍,等价于openAPI2.0的
description: API description in Markdown.
- 后面的Schemes/BasePath等都是OpenAPI2.0的相应元数据,不懂就回头看上面的教学(我这里验证的元数据没写,问题不大)
- 最后以swagger:meta结尾
回到main文件下,引入doc包
// main.go
import _ "xxxxxxxxx/doc"
在main文件所在的目录下执行命令 -o为生成目录地址,我这里选择生成yaml文件
swagger generate spec -o ../../doc/swagger.yaml
你可以检查下yaml文件是否为你需要的启动swagger服务器运行UI界面
swagger serve --no-open -F=swagger --port 36666 ../../doc/swagger.yaml
这是最初的界面
- --no-open 是不打开浏览器
- -F可选择UI风格swagger和redoc
- --port 为服务器端口
redoc如下
之后暂时关闭swagger服务器,添加接口,新建文件 /swagger/doc/user.go 用来保存接口
// swagger:parameters userInfo
type User struct {
//username of user info
//
// Required: true
// in: path
User string
}
// swagger:response usersrvResp
type Respon struct {
Code int
Data string
}
//swagger:route GET /users/{User} user userInfo
// 获取用户信息.
// responses:
// 200: usersrvResp
注意我这里使用路径参数 /v1/users/:User,因此需要对User结构体的User字段设置
in: path
再调用命令重写生成yaml文件,启动服务器之后我们就可以启动gin服务器进行联调了,和postman功能很像