gors
gors是一个代码生产器,基于个服务接口和描述,自动创建一个符合gin路由规则的服务.
快速开始
- 安装gors:
go install github.com/go-leo/gors/cmd/gors@latest
- 定义一个服务接口:
//go:generate gors -service Service
// Service
// @GORS @Path("/api) @Path("/v1)
type Service interface {
// Method
// @GORS @GET @Path("/method/:id) @UriBinding @JSONRender
Method(context.Context, *MethodReq) (*MethodResp, error)
}
type MethodReq struct {
ID int `uri:"id"`
}
type MethodResp struct {
V int `json:"v,omitempty"`
}
- 运行一下命令,生产文件service_gors.go
go generate ./...
// Code generated by "gors -service Service"; DO NOT EDIT.
package demo
import (
gin "github.com/gin-gonic/gin"
gors "github.com/go-leo/gors"
http "net/http"
)
func ServiceRoutes(srv Service) []gors.Route {
return []gors.Route{
{
HTTPMethod: http.MethodGet,
Path: "/api/v1/method/:id",
HandlerFunc: func(c *gin.Context) {
var req *MethodReq
var resp *MethodResp
var err error
req = new(MethodReq)
if err = c.BindUri(req); err != nil {
c.String(http.StatusBadRequest, err.Error())
_ = c.Error(err).SetType(gin.ErrorTypeBind)
return
}
if err := gors.Validate(req); err != nil {
c.String(http.StatusBadRequest, err.Error())
_ = c.Error(err).SetType(gin.ErrorTypeBind)
return
}
ctx := gors.NewContext(c)
resp, err = srv.Method(ctx, req)
if err != nil {
if httpErr, ok := err.(*gors.HttpError); ok {
c.String(httpErr.StatusCode(), httpErr.Error())
_ = c.Error(err).SetType(gin.ErrorTypePublic)
return
}
c.String(http.StatusInternalServerError, err.Error())
_ = c.Error(err).SetType(gin.ErrorTypePrivate)
return
}
statusCode := gors.GetCodeFromContext(ctx)
c.JSON(statusCode, resp)
},
},
}
}
- 实现服务接口
var _ demo.Service = new(Service)
type Service struct {}
func (svc *Service) Method(ctx context.Context, req *demo.MethodReq) (*demo.MethodResp, error) {
fmt.Println(req.ID)
return &demo.MethodResp{V: 10}, nil
}
- 创建gin.Engine,注册路由并启动http服务:
var routers []gors.Router
routers = append(routers, demo.ServiceRouters(new(svc.Service))...)
engine := gin.New()
for _, router := range routers {
engine.Handle(router.HTTPMethod, router.Path, router.HandlerFunc)
}
srv := http.Server{Handler: engine}
listen, err := net.Listen("tcp", ":8088")
if err != nil {
panic(err)
}
err = srv.Serve(listen)
if err != nil {
panic(err)
}
方法入参
参数一
第一个参数必须是context.Context
,其他类型都会生成失败。
参数二
第二个参数有四种类型:io.Reader
、[]byte
、string
和结构体指针
,其他类型都会生成失败。
io.Reader
,直接取http.Request
里的Body
。所有Binding策略都不能用。
[]byte
,将http.Request
里的Body
以字节数组形式全部读出。所有Binding策略都不能用。
string
,将http.Request
里的Body
以字符串形式全部读出。所有Binding策略都不能用。
结构体指针
,所有Binding策略都适用,将path、query、header和body中的参数,绑定到内部字段里。
响应
参数一
第一个响应参数有四种类型:string
、[]byte
、io.Reader
和结构体指针
,其他类型都会生成失败。
io.Reader
,将io.Reader
写入响应的Body中,必须要配合@ReaderRender
注解使用,可以自定义响应Content-Type
,比如@ReaderRender(video/mpeg4)
[]byte
,将[]byte
写入响应的Body中,必须要配合@BytesRender
注解使用,可以自定义响应Content-Type
,比如@BytesRender(image/png)
string
,可以配合不同的Render策略进行响应。
@TextRender
, 将文本以Content-Type
为"text/plain; charset=utf-8"
写入响应的Body中。
@HTMLRender
, 将文本以Content-Type
为"text/html; charset=utf-8"
写入响应的Body中。
@StringRender
, 将文本写入响应的Body中,可以自定义响应Content-Type
,比如@StringRender(text/xml)
@RedirectRender
, 重定向渲染,重定向到文本指定的位置。
结构体指针
,需要配合各自Render策略,将结构体指针序列化成[]byte
后,写入响应的Body中。
参数二
第一个请求参数必须是error
,其他类型都会生成失败。
如果error是*gors.HttpError
类型,将设置指定的status code,然后将错误的文本写入响应的Body。
否则会设置500的status code,然后将错误的文本写入响应的Body。
注解大全
@GORS
必须设置, 基础注解。
代表gors的注解配置的开始,没有@GORS
开始的都会被忽略。
@Path
必须设置,路径注解。
- 可以设置参数,
@Path(/api)
- 如果设置在接口名上,代表为所有path定义基础的path。
- 如果设置在方法上,代表为此方法定义path。
- 可以设置多个
@Path
注解,此时多个path会被拼接成一个。
HTTP Method注解
必须设置,设置此方法的只能响应指定的Method请求。 Method只能有一个有效,如果设置多个,只有最后一个有效。支持标准库里定义的9种method:
@GET
此注解设置此方法为Get请求。
@HEAD
此注解设置此方法为Head请求。
@POST
此注解设置此方法为Post请求。
@PUT
此注解设置此方法为Put请求。
@PATCH
此注解设置此方法为Patch请求。
@DELETE
此注解设置此方法为Delete请求。
@CONNECT
此注解设置此方法为Connect请求。
@OPTIONS
此注解设置此方法为Options请求。
@TRACE
此注解设置此方法为Trace请求。
Binding 注解
数据绑定注解。
- 当第二个参数是结构体指针时候,可以设置。
- 可以设置多种Binding策略。
@UriBinding
将对应的Uri参数绑定到结构体指针中。
支持gin的路径参数语法和gin的uri绑定策略
@QueryBinding
将对应的Query参数绑定到结构体指针中。
支持gin的只绑定Query策略。
将对应的Header参数绑定到结构体指针中。
支持gin的header绑定策略
@JSONBinding
将请求的Body以JSON形式解析出来,并绑定到结构体指针中。
@XMLBinding
将请求的Body以XML形式解析出来,并绑定到结构体指针中。
将请求的Query和Body同时以Form形式解析出来,并绑定到结构体指针中。
不支持文件上传。
支持gin的form绑定策略
@FormPostBinding
将请求的Body以FormPost形式解析出来,并绑定到结构体指针中。
只支持application/x-www-form-urlencoded
的Form请求。
不支持文件上传。
支持gin的urlencoded绑定策略
将请求的Body以Multipart形式解析出来并绑定到结构体指针中。
只支持multipart/form-data
的Form请求。
支持文件上传。
支持gin的Multipart绑定策略
@ProtoBufBinding
将请求的Body以protobuf形式解析出来并绑定到结构体指针中。
@MsgPackBinding
将请求的Body以msgpack形式解析出来并绑定到结构体指针中。
@YAMLBinding
将请求的Body以YAML形式解析出来并绑定到结构体指针中。
@TOMLBinding
将请求的Body以TOML形式解析出来并绑定到结构体指针中。
@CustomBinding
预定义的Binding策略不能满足需求,需要使用自定义Binding策略,请求结构体需要实现gors.Binding接口。
Render 注解
响应渲染注解。
- 方法的一个返回参数的类型不通,相对应的渲染也不同。
- 只能设置一种渲染策略。
@BytesRender
字节数组渲染。
只有当方法的第一个返回参数类型为[]byte
时才能使用,@BytesRender
将数据以字节数组写入响应的Body中,可以自定义响应Content-Type
,比如:@BytesRender(image/png)
代表渲染一张图片。
@StringRender
字符串渲染。
只有当方法的第一个返回参数类型为string
时才能使用,@StringRender
将数据以文本的方式写入响应的Body中,可以自定义响应Content-Type
,比如@StringRender(image/xml)
代表渲染xml文件。
@TextRender
文本渲染。
只有当方法的第一个返回参数类型为string
时才能使用,@TextRender
将数据以文本的方式写入响应的Body中,Content-Type
固定为text/plain; charset=utf-8
@HTMLRender
HTML渲染。
只有当方法的第一个返回参数类型为string
时才能使用,@HTMLRender
将数据以文本的方式写入响应的Body中,Content-Type
固定为text/html; charset=utf-8
@RedirectRender
重定向渲染。
只有当方法的第一个返回参数类型为string
时才能使用,此参数应该是个可以重定向的地址位置。
@ReaderRender
数据流渲染,只有当方法的第一个返回参数类型为io.Reader
时才能使用,@ReaderRender
将数据流写入响应的Body中,可以自定义响应Content-Type
,比如:@ReaderRender(video/mpeg4)
代表渲染一个视频文件。
@JSONRender
JSON渲染。
只有当方法的第一个返回参数类型为结构体指针
时才能使用,@JSONRender
将结构体指针以JSON格式序列化并且写入响应的Body中,Content-Type
固定为application/json; charset=utf-8
。参考gin文档-json
@IndentedJSONRender
漂亮的JSON渲染,在JSON渲染的基础上,加上了缩进和结束行。
只有当方法的第一个返回参数类型为结构体指针
时才能使用,@IndentedJSONRender
将结构体指针以JSON格式序列化并且写入响应的Body中,Content-Type
固定为application/json; charset=utf-8
。比较耗资源。
@SecureJSONRender
安全的的JSON渲染,防止一些代码注入。
只有当方法的第一个返回参数类型为结构体指针
时才能使用,@SecureJSONRender
将结构体指针以JSON格式序列化并且写入响应的Body中,Content-Type
固定为application/json; charset=utf-8
。gin文档-SecureJSON
@JsonpJSONRender
jsonp方式渲染,jsonp可以跨域请求,如果查询参数callback存在,则将callback添加到响应体中。
只有当方法的第一个返回参数类型为结构体指针
时才能使用。参考gin文档-jsonp
@PureJSONRender
纯净的JSON渲染,普通的JSON渲染,会将一些html特殊字符会被转义,比如<
转成\u003c
。@PureJSONRender
则不会转义。
只有当方法的第一个返回参数类型为结构体指针
时才能使用,@PureJSONRender
将结构体指针以JSON格式序列化并且写入响应的Body中,Content-Type
固定为application/json; charset=utf-8
。gin文档-PureJSON
@AsciiJSONRender
AsciiJSON渲染,只渲染Ascii字符,非Ascii字符则会被转义。
只有当方法的第一个返回参数类型为结构体指针
时才能使用,@AsciiJSONRender
将结构体指针以JSON格式序列化并且写入响应的Body中,Content-Type
固定为application/json; charset=utf-8
。gin文档-AsciiJSON
@XMLRender
XML渲染。
只有当方法的第一个返回参数类型为结构体指针
时才能使用,@XMLRender
将结构体指针以XML格式序列化并且写入响应的Body中,Content-Type
固定为application/xml; charset=utf-8
。参考gin文档-XMLRender
@YAMLRender
YAML渲染。
只有当方法的第一个返回参数类型为结构体指针
时才能使用,@YAMLRender
将结构体指针以YAML格式序列化并且写入响应的Body中,Content-Type
固定为application/x-yaml; charset=utf-8
。参考gin文档-YAMLRender
@ProtoBufRender
ProtoBuf渲染。
只有当方法的第一个返回参数类型为结构体指针
时才能使用,@ProtoBufRender
将结构体指针以Protocol Buffer格式序列化并且写入响应的Body中,Content-Type
固定为application/x-protobuf
。参考gin文档-ProtoBufRender
@MsgPackRender
MsgPack渲染。
只有当方法的第一个返回参数类型为结构体指针
时才能使用,@MsgPackRender
将结构体指针以MsgPack格式序列化并且写入响应的Body中,Content-Type
固定为application/msgpack; charset=utf-8
。
@TOMLRender
TOML渲染。
只有当方法的第一个返回参数类型为结构体指针
时才能使用,@TOMLRender
将结构体指针以TOML格式序列化并且写入响应的Body中,Content-Type
固定为application/toml
。参考gin文档-TOMLRender
@CustomRender
预定义的Render策略不能满足需求,需要使用自定义Render策略,响应结构体需要实现gors.Render接口。
Validate
除了gin框架支持的参数校验方案外,gors也提供了另外一种参数校验方式,方法的第一个返回参数类型为结构体指针
,并且实现了Validator接口,则在数据绑定后,会对数据进行校验。
Validator接口
type Validator interface {
Validate() error
}