fastapi

package module
v0.3.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 17, 2025 License: MIT Imports: 23 Imported by: 3

README

FastApi-Golang (包装器)

  • 类似python-FastApiGolang实现;
  • 提供OpenApi文档的自动生成,提供SwaggerRedoc文档;
  • 通过一次代码编写同时生成文档和参数校验,无需编写swagger的代码注释;
  • 直接在路由函数中使用经过校验的请求参数,无需通过ShouldBind等方法;
  • 支持请求参数的自动校验:
    • 包括:QueryPathHeaderCookieFormFile 参数的自动校验(HeaderCookieFormFile正在支持中)
    • Body参数的自动校验,支持json/multipart格式,json 基于validator
  • 包装器,不限制底层的HTTP框架,支持ginfiber等框架,并可轻松的集成到任何框架中;

Usage 使用说明:

go get https://github.com/Chendemo12/fastapi

快速实现

// 创建一个结构体实现fastapi.GroupRouter接口
type ExampleRouter struct {
	fastapi.BaseGroupRouter
}

func (r *ExampleRouter) Prefix() string { return "/api/example" }

// 定义一个 GET 请求,路由为 `/api/example/app-title`, 返回值为string,无请求参数
func (r *ExampleRouter) GetAppTitle(c *fastapi.Context) (string, error) {
	return "FastApi Example", nil
}


// 创建app
app := fastapi.New()
mux := fiberWrapper.Default()
app.SetMux(mux)
// 绑定路由
app.IncludeRouter(&ExampleRouter{})
// 启动
app.Run("0.0.0.0", "8090")

具体解释

  • 创建一个Wrapper对象:
import "github.com/Chendemo12/fastapi"

// 可选的 fastapi.Config 参数
app := fastapi.New(fastapi.Config{
    Version:     "v1.0.0",
    Description: "这是一段Http服务描述信息,会显示在openApi文档的顶部",
    Title:       "FastApi Example",
})

显示效果

显示效果
  • 指定底层HTTP路由器,也称为Mux, 为兼容不同的Mux,还需要对Mux进行包装,其定义为MuxWrapper
import "github.com/Chendemo12/fastapi/middleware/fiberWrapper"

// 此处采用默认的内置Fiber实现, 必须在Run启动之前设置
mux := fiberWrapper.Default()
app.SetMux(mux)

// 或者自定义Fiber实现
fiberEngine := fiber.New(fiber.Config{
    Prefork:       false,                   // 多进程模式
    CaseSensitive: true,                    // 区分路由大小写
    StrictRouting: true,                    // 严格路由
    ServerHeader:  "FastApi",               // 服务器头
    AppName:       "fastapi.fiber",         // 设置为 Response.Header.Server 属性
    ColorScheme:   fiber.DefaultColors,     // 彩色输出
    JSONEncoder:   utils.JsonMarshal,       // json序列化器
    JSONDecoder:   utils.JsonUnmarshal,     // json解码器
})                                          // 创建fiber引擎
mux := fiberWrapper.NewWrapper(fiberEngine) // 创建fiber包装器
app.SetMux(mux)
  • 创建路由: 实现fastapi.GroupRouter接口,并创建方法以定义路由:
// 创建一个结构体实现fastapi.GroupRouter接口
type ExampleRouter struct {
	fastapi.BaseGroupRouter
}

func (r *ExampleRouter) Prefix() string { return "/api/example" }

func (r *ExampleRouter) GetAppTitle(c *fastapi.Context) (string, error) {
	return "FastApi Example", nil
}

type UpdateAppTitleReq struct {
	Title string `json:"title" validate:"required" description:"App标题"`
}

func (r *ExampleRouter) PatchUpdateAppTitle(c *fastapi.Context, form *UpdateAppTitleReq) (*UpdateAppTitleReq, error) {
	return form, nil
}

// 注册路由
app.IncludeRouter(&ExampleRouter{})

显示效果

显示效果
  • 启动:
// 阻塞运行
app.Run("0.0.0.0", "8090") 

显示效果

显示效果

方法说明

路由方法定义
方法 说明
Prefix() string 路由组前缀
Tags() []string 分组标签
PathSchema() pathschema.RoutePathSchema 路由解析规则,对路由前缀和路由地址都有效
Summary() map[string]string 为路由添加摘要说明,key为原始的方法名,value为摘要
Description() map[string]string 为路由添加详细说明,key为原始的方法名,value为详细描述(支持markdown显示)
Path() map[string]string 自定义路径,可用于定义路径,key为原始的方法名,value为路径
  • 对于路由组ExampleRouter来说:
    • TagsExampleRouter
    • 路由组前缀为手动定义的/api/example
满足路由定义的方法要求:
  • 方法需为指针接收器
  • 方法必须是导出方法
  • 方法名必须以HTTP操作名开头或结尾:Post, Patch, Get, Delete, Put
  • 返回值必须为2个参数:(XXX, error), 第二个参数必须是error类型,第一个参数为任意参数,但不建议是map类型,不能是nil
  • 第一个入参必须是*fastapi.Context,
    • 对于Post, Patch, Put 至少有一个自定义参数作为请求体,如果不需要请求体参数则用fastapi.None代替
    • 对于Get, Delete只能有一个自定义结构体参数作为查询参数、cookies、header等参数
有关方法入参的解析规则:
  • 对于GetDelete
    • 有且只有一个结构体入参,被解释为查询/路径等参数
  • 对于Post, Patch, Put:
    • 最后一个入参被解释为请求体,其他入参除fastapi.File外被解释为查询/路径等参数
参数定义
  • 建议用结构体来定义所有参数:
  • 参数的校验和文档的生成遵循Validator的标签要求
  • 任何情况下json标签都会被解释为参数名,对于查询参数则优先采用query标签名
  • 任何模型都可以通过SchemaDesc() string方法来添加模型说明,作用等同于python.__doc__属性
文件上传
  • 通过在Post, Put, Patch 方法中添加*fastapi.File参数,即可实现文件上传;
  • 请求体类型固定为multipart/form-data
// 仅上传文件
func (r *ExampleRouter) PostUploadFile(c *fastapi.Context, file *fastapi.File) (int64, error) {
	return 1, nil
}

type UpdateUserInfoReq struct {
	Name  string `json:"name" validate:"required"`
	Email string `json:"email" validate:"required"`
}

// 上传文件和json数据
func (r *ExampleRouter) PostUploadFileWithForm(c *fastapi.Context, file *fastapi.File, param *UpdateUserInfoReq) (int64, error) {
	return 1, nil
}

注意:

当同时存在文件和json参数时,请把fastapi.File放在json参数之前, PostUploadFileWithForm(c *fastapi.Context, file *fastapi.File, param *UpdateUserInfoReq), 此情况下,json参数会作为请求体参数; 如果fastapi.File放在json参数之后,则json参数会作为query参数,如 PostUploadFileWithForm(c *fastapi.Context, param *UpdateUserInfoReq, file *fastapi.File)

由于反射过程中无法获得参数的名称,所以文件和json部分的字段名默认为fileparam, 但可通过以下方法进行修改(必须在启动前设置):

fastapi.SetMultiFormFileName("files")
fastapi.SetMultiFormParamName("data")
文件下载
  • 通过返回*fastapi.FileResponse对象来向客户端发送文件;
// 以附件形式下载文件
func (r *ExampleRouter) GetFileAttachment(c *fastapi.Context, param *DownloadFileReq) (*fastapi.FileResponse, error) {
	return fastapi.FileAttachment("../README.md", "README.md"), nil
}

// 直接发送文件内容给客户端
func (r *ExampleRouter) GetSendFile(c *fastapi.Context) (*fastapi.FileResponse, error) {
	return fastapi.SendFile("../README.md"), nil
}

  • 对于文件下载支持以下方式:
方法 作用
SendFile 向客户端发送本地文件,此时会读取文件内容,并将文件内容作为响应体返回给客户端
FileAttachment 以附件形式返回本地文件,自动设置"Content-Disposition",浏览器会触发自动下载
FileFromReader 从io.Reader中读取文件并返回给客户端
Stream 发送字节流到客户端,Content-Type为application/octet-stream
路由url解析 RoutePathSchema
  • 方法开头或结尾中包含的http方法名会被忽略,对于方法中包含多个关键字的仅第一个会被采用:

    • PostDelet - > 路由为delte, 方法为Post
  • 允许通过PathSchema() pathschema.RoutePathSchema来自定义解析规则,支持以下规则:

    • LowerCaseDash:全小写-短横线
    • LowerCaseBackslash:全小写段路由
    • LowerCamelCase:将结构体名称按单词分割后转换为小驼峰的形式后作为相对路由
    • LowerCase:将方法名按单词分割后全部转换为小写字符再直接拼接起来
    • UnixDash/ Dash:将方法名按单词分割后用"-"相连接
    • Underline:将方法名按单词分割后用"_"相连接
    • Backslash:按单词分段,每一个单词都作为一个路由段
    • Original:原始不变,保持结构体方法名(不含HTTP方法名),只拼接成合法的路由
    • AddPrefix:用于在分段路由基础上添加一个前缀字符,作用于每一段路径,通常与其他方案组合使用
    • AddSuffix:用于在分段路由基础上添加一个后缀字符,作用于每一段路径,通常与其他方案组合使用
    • Composition:组合式路由格式化方案, 通过按顺序执行多个 RoutePathSchema 获得最终路由
  • 详细示例可见 pathschema_test.go

Config 配置项 app.go:Config
参数 作用 是否必选 默认值
Title APP标题 1.0.0
Version APP版本号 FastAPI Application
Description APP描述 FastAPI
ShutdownTimeout 平滑关机,单位秒 5
DisableSwagAutoCreate 禁用OpenApi文档,但是不禁用参数校验 false
StopImmediatelyWhenErrorOccurs 是否在遇到错误字段时立刻停止校验, 对于有多个请求参数时,默认会检查每一个参数是否合法,并最终返回所有的错误参数信息,设为true以在遇到一个错误参数时停止后续的参数校验并直接返回错误信息。 false
ContextAutomaticDerivationDisabled 禁止为每一个请求创建单独的context.Context 。为每一个请求单独创建一个派生自Wrapper.Context()的ctx是十分昂贵的开销,但有时有时十分必要的,禁用后调用 Context.Context() 将会产生错误 false
Wrapper 配置项 app.go:Wrapper
添加启动/关闭前同步事件 ,等同于 FastAPI.on_event(),
  • event_type: startup / shutdown
  • 同步执行,应避免阻塞;
  • startup 会在初始化完成后、listen之前依次调用;
  • shutdown 会在Context cancel 之后,mux shutdown之前依次调用;
设置设置路由错误信息格式化函数 SetRouteErrorFormatter
  • 由于路由方法handler的定义中,其返回值必须有2个参数,且最后一个参数必须为 error 接口,因此当handler 返回错误时,如何合理的返回错误消息也十分的重要;

  • 默认情况下当handler返回错误时,Wrapper 会返回500错误码string类型的错误消息; 错误消息

  • 允许通过 Wrapper.SetRouteErrorFormatter 方法来自定义错误消息:

// 自定义错误格式
type ErrorMessage struct {
    Code      string `json:"code,omitempty" description:"错误码"`
    Message   string `json:"message,omitempty" description:"错误信息"`
    Timestamp int64  `json:"timestamp,omitempty"`
}

// 格式化路由函数错误消息
func FormatErrorMessage(c *fastapi.Context, err error) (statusCode int, message any) {
    return 400, &ErrorMessage{
        Code:      "0x1234",
        Message:   err.Error(),
        Timestamp: time.Now().Unix(),
    }
}

// 自定义错误格式,fastapi.RouteErrorOpt 仅用于添加文档说明
app.SetRouteErrorFormatter(FormatErrorMessage, fastapi.RouteErrorOpt{
  StatusCode:   400,
  ResponseMode: &ErrorMessage{},
  Description:  "服务器内部发生错误,请稍后重试",
})

显示效果

错误文档
  • 此时的接口返回值更新为:

显示效果

接口响应
  • RouteErrorFormatter的定义如下:
  // RouteErrorFormatter 路由函数返回错误时的处理函数,可用于格式化错误信息后返回给客户端
  //
  //	程序启动时会主动调用此方法用于生成openApi文档,所以此函数不应返回 map等类型,否则将无法生成openApi文档
  //
  //	当路由函数返回错误时,会调用此函数,返回值会作为响应码和响应内容, 返回值仅限于可以JSON序列化的消息体
  //	默认情况下,错误码为500,错误信息会作为字符串直接返回给客户端
  type RouteErrorFormatter func(c *Context, err error) (statusCode int, resp any)
  • 其中实际接口响应的状态码以RouteErrorFormatter的返回值为准,而非fastapi.RouteErrorOpt中的配置, fastapi.RouteErrorOpt的配置仅仅作用于文档显示。
使用请求钩子 DependenceHandle
// DependenceHandle 依赖/钩子函数 Depends/Hook
type DependenceHandle func (c *Context) error
  • 对于Wrapper而言,其本质是一个装饰器,是对具体的Mux的包装,因此其自身并没有中间件的概念,同时也是为了避免与Mux 的中间件引起冲突,有关的WraperMux的核心交互定义如下:
  • Wraper会将使用者定义的每一个handler进行二次包装,并作为Muxhandler注册到路由器上,其包装后的定义如下:
  // Handler 路由函数,实现逻辑类似于装饰器
  //
  // 路由处理方法(装饰器实现),用于请求体校验和返回体序列化,同时注入全局服务依赖,
  // 此方法接收一个业务层面的路由钩子方法 RouteIface.Call
  //
  // 方法首先会查找路由元信息,如果找不到则直接跳过验证环节,由路由器返回404
  // 反之:
  //
  //  1. 申请一个 Context, 并初始化请求体、路由参数等
  //  2. 之后会校验并绑定路由参数(包含路径参数和查询参数)是否正确,如果错误则直接返回422错误,反之会继续序列化并绑定请求体(如果存在)序列化成功之后会校验请求参数的正确性,
  //  3. 校验通过后会调用 RouteIface.Call 并将返回值绑定在 Context 内的 Response 上
  //  4. 校验返回值,并返回422或将返回值写入到实际的 response
  func (f *Wrapper) Handler(ctx MuxContext) error {}
  • 建议将跨域访问Recover等方法注册为Mux的中件间;而将日志、认证等业务方法注册为Wraper 的依赖,但是其2者并没有十分明显的区别,绝大部分情况都可以互相替换;

  • Wraper.Handler 的实现是一个顺序执行的过程,其作为一个整体,因此是无法在Mux的中间件中对其进行访问和拦截的,为此 Wraper暴露出了一些锚点,用于控制Wraper.Handler的执行流:

    • Wrapper.UsePrevious: 添加一个校验前依赖函数,此依赖函数会在:请求参数校验前调用

    • Wrapper.UseAfter: 添加一个校验后依赖函数(也即路由前), 此依赖函数会在:请求参数校验后-路由函数调用前执行

    • Wrapper.UseBeforeWrite: 在数据写入响应流之前执行的钩子方法; 可用于日志记录, 所有请求无论何时终止都会执行此方法

    • Wrapper.UseUseAfter的别名

      // Use 添加一个依赖函数(锚点), 数据校验后依赖函数
      //
      // 由于 Wrapper 的核心实现类似于装饰器, 而非常规的中间件,因此无法通过 MuxWrapper 的中间件来影响到 Wrapper 的执行过程;
      // 因此 Wrapper 在关键环节均定义了相关的依赖函数,类似于hook,以此来控制执行流程;
      //
      //	与python-FastApi的Depends不同的地方在于:
      //		python-FastApi.Depends接收Request作为入参,并将其返回值作为路由函数Handler的入参;
      //		而此处的hook不返回值,而是通过 Context.Set 和 Context.Get 来进行上下文数据的传递,并通过返回 error 来终止后续的流程;
      //		同时,由于 Context.Set 和 Context.Get 是线程安全的,因此可以放心的在依赖函数中操作 Context;
      //	   	依赖函数的执行始终是顺序进行的,其执行顺序是固定的:
      //	   	始终由 UsePrevious -> (请求参数)Validate -> UseAfter -> (路由函数)RouteHandler -> (响应参数)Validate -> UseBeforeWrite -> exit;
      //
      // 此处的依赖函数有校验前依赖函数和校验后依赖函数,分别通过 Wrapper.UsePrevious 和 Wrapper.UseAfter 注册;
      // 当请求参数校验失败时不会执行 Wrapper.UseAfter 依赖函数, 请求参数会在 Wrapper.UsePrevious 执行完成之后被触发;
      // 如果依赖函数要终止后续的流程,应返回 error, 错误消息会作为消息体返回给客户端, 响应数据格式默认为500+string,可通过 Wrapper.SetRouteErrorFormatter 进行修改;
      func (f *Wrapper) Use(hooks ...DependenceHandle) *Wrapper {
          return f.UseAfter(hooks...)
      }
      
    • 使用示例:

      func BeforeValidate(c *fastapi.Context) error {
          c.Set("before-validate", time.Now())
      
          return nil
      }
      
      func PrintRequestLog(c *fastapi.Context) {
          fastapi.Info("请求耗时: ", time.Since(c.GetTime("before-validate")))
          fastapi.Info("响应状态码: ", c.Response().StatusCode)
      }
      
      func returnErrorDeps(c *fastapi.Context) error {
          return errors.New("deps return error")
      }
      
      app.UsePrevious(BeforeValidate)
      app.Use(returnErrorDeps)
      app.UseBeforeWrite(PrintRequestLog)
      

      显示效果

      显示效果
      2024/04/27 17:47:38 group_router_test.go:522: INFO	请求耗时:  10.372µs
      2024/04/27 17:47:38 group_router_test.go:523: INFO	响应状态码:  400
      2024-04-27 17:47:38    GET	/api/example/error    400
      2024/04/27 17:47:38 group_router_test.go:522: INFO	请求耗时:  11.855µs
      2024/04/27 17:47:38 group_router_test.go:523: INFO	响应状态码:  400
      2024-04-27 17:47:38    GET	/api/example/error    400
      2024/04/27 17:47:38 group_router_test.go:522: INFO	请求耗时:  6.739µs
      2024/04/27 17:47:38 group_router_test.go:523: INFO	响应状态码:  400
      2024-04-27 17:47:38    GET	/api/example/error    400
      

二次开发选项

TODO

查看在线文档

# 安装godoc
go install golang.org/x/tools/cmd/godoc@latest
godoc -http=:6060

# 或:pkgsite 推荐
go install golang.org/x/pkgsite/cmd/pkgsite@latest
cd fastapi-go/
pkgsite -http=:6060 -list=false
# 浏览器打开:http://127.0.0.1:6060/github.com/Chendemo12/fastapi

struct内存对齐

go install golang.org/x/tools/go/analysis/passes/fieldalignment/cmd/fieldalignment@latest

fieldalignment -fix ./... 

打包静态资源文件

# 安装工具
go get -u github.com/go-bindata/go-bindata/...
go install github.com/go-bindata/go-bindata/...

# 下载资源文件
#https://fastapi.tiangolo.com/img/favicon.png
#https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css
#https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js
#https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js

# 打包资源文件到openapi包
go-bindata -o openapi/css.go --pkg openapi internal/static/...

Documentation

Overview

Package fastapi FastApi-Python 的Golang实现

其提供了类似于FastAPI的API设计,并提供了接口文档自动生成、请求体自动校验和返回值自动序列化等使用功能;

Index

Constants

View Source
const (
	ReceiverParamOffset      = 0                      // 接收器参数的索引位置
	FirstInParamOffset       = 1                      // 第一个有效参数的索引位置,由于结构体接收器处于第一位置
	FirstCustomInParamOffset = FirstInParamOffset + 1 // 第一个自定义参数的索引位置
	FirstOutParamOffset      = 0
	LastOutParamOffset       = 1 // 最后一个返回值参数的索引位置
	OutParamNum              = 2
)
View Source
const (
	FirstInParamName = "Context" // 第一个入参名称
	LastOutParamName = "error"   // 最后一个出参名称
)
View Source
const (
	ModelNotDefine     = "Data model is undefined"
	ModelNotMatch      = "Value type mismatch"
	ModelCannotString  = "The return value cannot be a string"
	ModelCannotNumber  = "The return value cannot be a number"
	ModelCannotInteger = "The return value cannot be a integer"
	ModelCannotBool    = "The return value cannot be a boolean"
	ModelCannotArray   = "The return value cannot be a array"
	PathPsIsEmpty      = "Path must not be empty"
	QueryPsIsEmpty     = "Query must not be empty"
)
View Source
const (
	Version   = "0.3.1"
	Copyright = "chendemo12"
	Website   = "https://github.com/Chendemo12"
)
View Source
const DefaultErrorStatusCode = http.StatusInternalServerError
View Source
const HttpMethodMinimumLength = len(http.MethodGet)
View Source
const WebsocketMethod = "WS"

Variables

View Source
var (
	ReflectObjectType = utils.ReflectObjectType
	SetJsonEngine     = utils.SetJsonEngine
)
View Source
var Debug func(args ...any)
View Source
var Debugf func(format string, v ...any)
View Source
var Error func(args ...any)
View Source
var Errorf func(format string, v ...any)
View Source
var IllegalLastInParamType = append(openapi.IllegalRouteParamType, reflect.Ptr)

IllegalLastInParamType 非法的请求体类型, 不支持指针的指针

IllegalResponseType 非法的返回值类型, 不支持指针的指针

View Source
var Info func(args ...any)
View Source
var Warn func(args ...any)
View Source
var Warnf func(format string, v ...any)

Functions

func Iter added in v0.2.0

func Iter[T any, S any](seq []S, fc func(elem S) T) []T

func LazyInit added in v0.2.0

func LazyInit()

func ParseJsoniterError added in v0.2.0

func ParseJsoniterError(err error, loc openapi.RouteParamType, objName string) *openapi.ValidationError

ParseJsoniterError 将jsoniter 的反序列化错误转换成 接口错误类型

func ParseValidatorError added in v0.2.0

func ParseValidatorError(err error, loc openapi.RouteParamType, objName string) []*openapi.ValidationError

ParseValidatorError 解析Validator的错误消息 如果不存在错误,则返回nil; 如果 err 是 validator.ValidationErrors 的错误, 则解析并返回详细的错误原因,反之则返回模糊的错误原因

func ReleaseResponse added in v0.2.0

func ReleaseResponse(resp *Response)

func ReplaceLogger added in v0.2.9

func ReplaceLogger(logger LoggerIface)

func SetMultiFormFileName added in v0.3.1

func SetMultiFormFileName(name string)

SetMultiFormFileName 设置表单数据中文件的字段名(键名称)

func SetMultiFormParamName added in v0.3.1

func SetMultiFormParamName(name string)

SetMultiFormParamName 设置表单数据中json参数的字段名(键名称)

Types

type BaseGroupRouter added in v0.2.0

type BaseGroupRouter struct {
}

BaseGroupRouter (面向对象式)路由组基类 需实现 GroupRouter 接口

其中以 Get,Post,Delete,Patch,Put 字符串(不区分大小写)开头或结尾并以 (XXX, error)形式为返回值的方法会被作为路由处理 其url的确定按照 RoutePathSchema 接口进行解析。

对于作为路由的方法签名有如下要求:

1:参数:

	第一个参数必须为 *Context
	如果有多个参数, 除第一个参数和最后一个参数允许为结构体外, 其他参数必须为基本数据类型
	对于Get/Delete:除第一个参数外的其他参数均被作为查询参数处理,如果为一个结构体,则对结构体字段进行解析并确定是否必选,如果为基本类型则全部为可选参数;
	对于Post/Patch/Put: 其最后一个参数必须为一个 struct指针,此参数会作为请求体进行处理,其他参数则=全部为可选的查询参数

2:返回值

	有且仅有2个返回值 (XXX, error)
	其中XXX会作为响应体模型,若error!=nil则返回错误; 如果返回值XXX=nil则无响应体

对于上述参数和返回值XXX,其数据类型不能是 接口,函数,通道,指针的指针;
只能是以下类型:~int, ~float, ~string, ~slice, ~struct, ~map, 结构体指针;
对于结构体类型,最好实现了 SchemaIface 接口

func (*BaseGroupRouter) Description added in v0.2.0

func (g *BaseGroupRouter) Description() map[string]string

func (*BaseGroupRouter) Path added in v0.2.0

func (g *BaseGroupRouter) Path() map[string]string

func (*BaseGroupRouter) PathSchema added in v0.2.0

func (g *BaseGroupRouter) PathSchema() pathschema.RoutePathSchema

func (*BaseGroupRouter) Prefix added in v0.2.0

func (g *BaseGroupRouter) Prefix() string

func (*BaseGroupRouter) Summary added in v0.2.0

func (g *BaseGroupRouter) Summary() map[string]string

func (*BaseGroupRouter) Tags added in v0.2.0

func (g *BaseGroupRouter) Tags() []string

type BaseModel

type BaseModel struct{}

BaseModel 基本数据模型, 对于上层的路由定义其请求体和响应体都应为继承此结构体的结构体 在 OpenApi 文档模型中,此模型的类型始终为 "object" 对于 BaseModel 其字段仍然可能会是 BaseModel

func (*BaseModel) IsRequired added in v0.2.0

func (b *BaseModel) IsRequired() bool

func (*BaseModel) SchemaDesc added in v0.2.0

func (b *BaseModel) SchemaDesc() string

SchemaDesc 结构体文档注释

func (*BaseModel) SchemaType added in v0.2.0

func (b *BaseModel) SchemaType() openapi.DataType

SchemaType 模型类型

type BaseRouter added in v0.2.0

type BaseRouter = BaseGroupRouter

type BoolModelBinder added in v0.3.1

type BoolModelBinder struct {
	// contains filtered or unexported fields
}

func (*BoolModelBinder) ModelName added in v0.3.1

func (m *BoolModelBinder) ModelName() string

func (*BoolModelBinder) Name added in v0.3.1

func (m *BoolModelBinder) Name() string

func (*BoolModelBinder) RouteParamType added in v0.3.1

func (m *BoolModelBinder) RouteParamType() openapi.RouteParamType

func (*BoolModelBinder) Validate added in v0.3.1

func (m *BoolModelBinder) Validate(c *Context, requestParam any) (any, []*openapi.ValidationError)

Validate data 为字符串类型

type Config added in v0.1.4

type Config struct {
	Title                 string `json:"title,omitempty" description:"程序名,同时作为日志文件名"`
	Description           string `json:"description,omitempty" description:"APP描述"`
	Version               string `json:"version,omitempty" description:"APP版本号"`
	ShutdownTimeout       int    `json:"shutdown_timeout,omitempty" description:"平滑关机,单位秒"`
	DisableSwagAutoCreate bool   `json:"disable_swag_auto_create,omitempty" description:"禁用OpenApi文档,但是不禁用参数校验"`
	// 默认情况下当请求校验过程遇到错误字段时,仍会继续向下校验其他字段,并最终将所有的错误消息一次性返回给调用方-
	// 当此设置被开启后,在遇到一个错误的参数时,会立刻停止终止流程,直接返回错误消息
	StopImmediatelyWhenErrorOccurs     bool `json:"stopImmediatelyWhenErrorOccurs" description:"是否在遇到错误字段时立刻停止校验"`
	ContextAutomaticDerivationDisabled bool `json:"contextAutomaticDerivationDisabled,omitempty" description:"禁止为每一个请求创建单独的Context"`
	DisableResponseValidate            bool `json:"disableResponseValidate" description:"是否禁用响应参数校验,仅JSON类型有效"`
	// contains filtered or unexported fields
}

func (*Config) Copy added in v0.3.1

func (c *Config) Copy() *Config

func (*Config) ListenAddr added in v0.3.1

func (c *Config) ListenAddr() string

type Context

type Context struct {

	// 每个请求专有的K/V
	Keys map[string]any
	// contains filtered or unexported fields
}

Context 路由上下文信息, 也是钩子函数的操作句柄

此结构体内包含了响应体 Response 以减少在路由处理过程中的内存分配和复制

注意: 当一个路由被执行完毕时, 路由函数中的 Context 将被立刻释放回收, 因此在return之后对
Context 的任何引用都是不对的, 若需在return之后监听 Context.Context() 则应该显式的复制或派生

func (*Context) Context added in v0.2.0

func (c *Context) Context() context.Context

Context 针对此次请求的唯一context, 当路由执行完毕返回时,将会自动关闭 <如果 ContextAutomaticDerivationDisabled = true 则异常>

为每一个请求创建一个新的 context.Context 其代价是非常高的,因此允许通过设置关闭此功能

@return	context.Context 当前请求的唯一context

func (*Context) Done

func (c *Context) Done() <-chan struct{}

Done 监听 Context 是否完成退出 <如果 ContextAutomaticDerivationDisabled = true 则异常>

@return	chan struct{} 是否退出

func (*Context) F

func (c *Context) F(s ...string) string

F 合并字符串

func (*Context) Get added in v0.2.2

func (c *Context) Get(key string) (value any, exists bool)

Get 从上下文中读取键值, ie: (value, true). 如果不存在则返回 (nil, false) Get returns the value for the given key, ie: (value, true). If the value does not exist it returns (nil, false)

func (*Context) GetBool added in v0.2.2

func (c *Context) GetBool(key string) (b bool)

GetBool 以bool形式读取键值 GetBool returns the value associated with the key as a boolean.

func (*Context) GetInt64 added in v0.2.2

func (c *Context) GetInt64(key string) (i64 int64)

GetInt64 以int64形式读取键值 GetInt64 returns the value associated with the key as an integer.

func (*Context) GetString added in v0.2.2

func (c *Context) GetString(key string) (s string)

GetString 以字符串形式读取键值 GetString returns the value associated with the key as a string.

func (*Context) GetTime added in v0.2.2

func (c *Context) GetTime(key string) (t time.Time)

GetTime 以time形式读取键值 GetTime returns the value associated with the key as time.

func (*Context) GetUint64 added in v0.2.2

func (c *Context) GetUint64(key string) (ui64 uint64)

GetUint64 以uint64形式读取键值 GetUint64 returns the value associated with the key as an unsigned integer.

func (*Context) MX added in v0.2.8

func (c *Context) MX() any

MX shortcut web引擎的上下文

func (*Context) Marshal

func (c *Context) Marshal(obj any) ([]byte, error)

func (*Context) MustGet added in v0.2.2

func (c *Context) MustGet(key string) any

MustGet 从上下文中读取键值,如果不存在则panic MustGet returns the value for the given key if it exists, otherwise it panics.

func (*Context) MuxContext added in v0.2.0

func (c *Context) MuxContext() MuxContext

MuxContext 获取web引擎的上下文

func (*Context) PathField added in v0.2.0

func (c *Context) PathField(name string, undefined ...string) string

PathField 获取路径参数 对于已经在路由处定义的路径参数,首先从 Context.pathFields 内部读取; 对于没有定义的其他查询参数则调用低层 MuxContext 进行解析

func (*Context) Query added in v0.2.0

func (c *Context) Query(name string, undefined ...string) any

Query 获取查询参数 对于已经在路由处定义的查询参数,首先从 Context.queryFields 内部读取 对于没有定义的其他查询参数则调用低层 MuxContext 进行解析

对于路由处定义的查询参数,参数类型会按照以下规则进行转换:

int 	=> int64
uint 	=> uint64
float 	=> float64
string 	=> string
bool 	=> bool

func (*Context) Response added in v0.2.2

func (c *Context) Response() *Response

Response 响应体,配合 Wrapper.UseBeforeWrite 实现在依赖函数中读取响应体内容,以进行日志记录等 !慎重对 Response 进行修改!

func (*Context) RootContext added in v0.2.3

func (c *Context) RootContext() context.Context

RootContext 根context 当禁用了context自动派生功能 <ContextAutomaticDerivationDisabled = true>,但又需要一个context时,可获得路由器Wrapper的context

func (*Context) Set added in v0.2.2

func (c *Context) Set(key string, value any)

Set 存储一个键值对,延迟初始化 !仅当 MuxContext 未实现此类方法时采用! Set is used to store a new key/value pair exclusively for this context. It also lazy initializes c.Keys if it was not used previously.

func (*Context) Status added in v0.2.0

func (c *Context) Status(code int)

Status 修改成功响应的状态码 由于路由组路由函数 GroupRouteHandler 签名的限制;当error!=nil时状态码默认为500,error==nil时默认为200 允许通过此方法修改当error=nil的响应状态码

func (*Context) Unmarshal

func (c *Context) Unmarshal(data []byte, v interface{}) error

func (*Context) Validator

func (c *Context) Validator() *validator.Validate

Validator 获取请求体验证器

type Ctx

type Ctx = Context

type DateModelBinder added in v0.3.1

type DateModelBinder struct {
	// contains filtered or unexported fields
}

DateModelBinder 日期校验

func (*DateModelBinder) ModelName added in v0.3.1

func (m *DateModelBinder) ModelName() string

func (*DateModelBinder) Name added in v0.3.1

func (m *DateModelBinder) Name() string

func (*DateModelBinder) RouteParamType added in v0.3.1

func (m *DateModelBinder) RouteParamType() openapi.RouteParamType

func (*DateModelBinder) Validate added in v0.3.1

func (m *DateModelBinder) Validate(c *Context, requestParam any) (any, []*openapi.ValidationError)

type DateTimeModelBinder added in v0.3.1

type DateTimeModelBinder struct {
	// contains filtered or unexported fields
}

DateTimeModelBinder 日期时间校验

func (*DateTimeModelBinder) ModelName added in v0.3.1

func (m *DateTimeModelBinder) ModelName() string

func (*DateTimeModelBinder) Name added in v0.3.1

func (m *DateTimeModelBinder) Name() string

func (*DateTimeModelBinder) RouteParamType added in v0.3.1

func (m *DateTimeModelBinder) RouteParamType() openapi.RouteParamType

func (*DateTimeModelBinder) Validate added in v0.3.1

func (m *DateTimeModelBinder) Validate(c *Context, requestParam any) (any, []*openapi.ValidationError)

type DefaultLogger added in v0.2.0

type DefaultLogger struct {
	// contains filtered or unexported fields
}

DefaultLogger 默认的控制台日志具柄

func NewDefaultLogger added in v0.2.0

func NewDefaultLogger() *DefaultLogger

func NewLogger added in v0.2.0

func NewLogger(out io.Writer, prefix string, flag int) *DefaultLogger

func (*DefaultLogger) Debug added in v0.2.0

func (l *DefaultLogger) Debug(args ...any)

func (*DefaultLogger) Debugf added in v0.2.0

func (l *DefaultLogger) Debugf(format string, v ...any)

func (*DefaultLogger) Error added in v0.2.0

func (l *DefaultLogger) Error(args ...any)

func (*DefaultLogger) Errorf added in v0.2.0

func (l *DefaultLogger) Errorf(format string, v ...any)

func (*DefaultLogger) Info added in v0.2.0

func (l *DefaultLogger) Info(args ...any)

func (*DefaultLogger) Warn added in v0.2.0

func (l *DefaultLogger) Warn(args ...any)

func (*DefaultLogger) Warnf added in v0.2.0

func (l *DefaultLogger) Warnf(format string, v ...any)

type DependenceHandle added in v0.2.4

type DependenceHandle func(c *Context) error

DependenceHandle 依赖函数 Depends/Hook

type Dict

type Dict = map[string]any // python.Dict

type Event

type Event struct {
	Fc   func()
	Type EventKind // 事件类型:startup 或 shutdown
}

Event 事件

type EventKind

type EventKind string

EventKind 事件类型

const (
	StartupEvent  EventKind = "startup"
	ShutdownEvent EventKind = "shutdown"
)

type FastApi

type FastApi = Wrapper

type File added in v0.3.1

type File struct {
	// contains filtered or unexported fields
}

File 上传文件 通过声明此类型, 以接收来自用户的上传文件 上传文件类型, 必须与 FileModelPkg 保持一致

func (*File) Files added in v0.3.1

func (f *File) Files() []*multipart.FileHeader

func (*File) First added in v0.3.1

func (f *File) First() *multipart.FileHeader

First 获取第一个文件, 需自行确认文件数量,否则会panic

func (*File) Open added in v0.3.1

func (f *File) Open(index int) (multipart.File, error)

func (*File) OpenFirst added in v0.3.1

func (f *File) OpenFirst() (multipart.File, error)

func (*File) RangeFile added in v0.3.1

func (f *File) RangeFile(fc func(file *multipart.FileHeader) (next bool))

type FileModelBinder added in v0.3.1

type FileModelBinder struct {
	// contains filtered or unexported fields
}

FileModelBinder 文件请求体验证

func (*FileModelBinder) ModelName added in v0.3.1

func (m *FileModelBinder) ModelName() string

func (*FileModelBinder) Name added in v0.3.1

func (m *FileModelBinder) Name() string

func (*FileModelBinder) RouteParamType added in v0.3.1

func (m *FileModelBinder) RouteParamType() openapi.RouteParamType

func (*FileModelBinder) Validate added in v0.3.1

func (m *FileModelBinder) Validate(c *Context, requestParam any) (any, []*openapi.ValidationError)

type FileResponse added in v0.3.1

type FileResponse struct {
	// contains filtered or unexported fields
}

FileResponse 返回文件或消息流

func FileAttachment added in v0.3.1

func FileAttachment(filepath, filename string) *FileResponse

FileAttachment 以附件形式返回本地文件,自动设置"Content-Disposition",浏览器会触发自动下载

func FileFromReader added in v0.3.1

func FileFromReader(reader io.Reader, filename string) *FileResponse

FileFromReader 从io.Reader中读取文件并返回给客户端

func SendFile added in v0.3.1

func SendFile(filepath string) *FileResponse

SendFile 向客户端发送本地文件,此时会读取文件内容,并将文件内容作为响应体返回给客户端

func Stream added in v0.3.1

func Stream(reader io.Reader) *FileResponse

Stream 发送字节流到客户端,Content-Type为application/octet-stream

func (*FileResponse) SchemaDesc added in v0.3.1

func (m *FileResponse) SchemaDesc() string

type FileResponseMode added in v0.3.1

type FileResponseMode int
const (
	FileResponseModeSendFile       FileResponseMode = iota // 直接发送本地文件
	FileResponseModeFileAttachment                         // 触发浏览器下载文件
	FileResponseModeReaderFile                             // 从reader中直接返回文件
	FileResponseModeStream                                 // 返回任意的数据流
)

type FileWithParamModelBinder added in v0.3.1

type FileWithParamModelBinder struct {
	FileModelBinder
	// contains filtered or unexported fields
}

FileWithParamModelBinder 文件+json 混合请求体验证

func (*FileWithParamModelBinder) Name added in v0.3.1

func (m *FileWithParamModelBinder) Name() string

func (*FileWithParamModelBinder) Validate added in v0.3.1

func (m *FileWithParamModelBinder) Validate(c *Context, requestParam any) (any, []*openapi.ValidationError)

type Finder added in v0.2.0

type Finder[T RouteIface] interface {
	Init(items []T) // 通过固定元素初始化查找器
	Get(id string) (T, bool)
	Range(fn func(item T) bool)
}

Finder 固定元素的查找器 用于从一个固定的元素集合内依据唯一标识来快速查找元素

func DefaultFinder added in v0.2.0

func DefaultFinder() Finder[RouteIface]

type FloatModelBinder added in v0.3.1

type FloatModelBinder[T constraints.Float | ~string] struct {
	// contains filtered or unexported fields
}

func (*FloatModelBinder[T]) ModelName added in v0.3.1

func (m *FloatModelBinder[T]) ModelName() string

func (*FloatModelBinder[T]) Name added in v0.3.1

func (m *FloatModelBinder[T]) Name() string

func (*FloatModelBinder[T]) RouteParamType added in v0.3.1

func (m *FloatModelBinder[T]) RouteParamType() openapi.RouteParamType

func (*FloatModelBinder[T]) Validate added in v0.3.1

func (m *FloatModelBinder[T]) Validate(c *Context, requestParam any) (any, []*openapi.ValidationError)

Validate 验证并转换数据类型 如果是string类型,则按照定义进行转换,反之则直接返回

type GroupRoute added in v0.2.0

type GroupRoute struct {
	// contains filtered or unexported fields
}

GroupRoute 路由组路由定义

func NewGroupRoute added in v0.2.0

func NewGroupRoute(swagger *openapi.RouteSwagger, method reflect.Method, group *GroupRouterMeta) *GroupRoute

func (*GroupRoute) Call added in v0.2.0

func (r *GroupRoute) Call(in []reflect.Value) []reflect.Value

Call 调用API, 并将响应结果写入 Response 内

func (*GroupRoute) HasFileRequest added in v0.3.1

func (r *GroupRoute) HasFileRequest() bool

func (*GroupRoute) HasStructQuery added in v0.2.0

func (r *GroupRoute) HasStructQuery() bool

func (*GroupRoute) Id added in v0.2.0

func (r *GroupRoute) Id() string

func (*GroupRoute) Init added in v0.2.0

func (r *GroupRoute) Init() (err error)

func (*GroupRoute) NewInParams added in v0.2.0

func (r *GroupRoute) NewInParams(ctx *Context) []reflect.Value

func (*GroupRoute) NewRequestModel added in v0.2.0

func (r *GroupRoute) NewRequestModel() any

func (*GroupRoute) NewStructQuery added in v0.2.0

func (r *GroupRoute) NewStructQuery() any

NewStructQuery 构造一个新的结构体查询参数实例

func (*GroupRoute) QueryBinders added in v0.2.0

func (r *GroupRoute) QueryBinders() []ModelBinder

QueryBinders 查询参数校验方法

func (*GroupRoute) RequestBinders added in v0.2.0

func (r *GroupRoute) RequestBinders() ModelBinder

func (*GroupRoute) ResponseBinder added in v0.2.0

func (r *GroupRoute) ResponseBinder() ModelBinder

func (*GroupRoute) RouteType added in v0.2.0

func (r *GroupRoute) RouteType() RouteType

func (*GroupRoute) Scan added in v0.2.0

func (r *GroupRoute) Scan() (err error)

func (*GroupRoute) ScanInner added in v0.2.0

func (r *GroupRoute) ScanInner() (err error)

ScanInner 解析内部 openapi.RouteSwagger 数据

func (*GroupRoute) Swagger added in v0.2.0

func (r *GroupRoute) Swagger() *openapi.RouteSwagger

type GroupRouteHandler added in v0.2.0

type GroupRouteHandler func(c *Context, params ...any) (any, error)

GroupRouteHandler 路由组路由函数签名,其中any可以是具体的类型,但不应该是 Response

type GroupRouter added in v0.2.0

type GroupRouter interface {
	// Prefix 路由组前缀,无需考虑是否以/开头或结尾,如果为空则通过 PathSchema 方案进行格式化
	Prefix() string
	// Tags 标签,如果为空则设为结构体名称的大驼峰形式,去掉可能存在的http方法名
	Tags() []string
	// PathSchema 路由解析规则,对路由前缀和路由地址都有效
	PathSchema() pathschema.RoutePathSchema
	// Summary 允许对单个方法路由的文档摘要信息进行定义
	// 方法名:摘要信息
	Summary() map[string]string
	// Description 方法名:描述信息
	Description() map[string]string
	// Path 允许对方法的路由进行重载, 方法名:相对路由
	// 由于以函数名确定方法路由的方式暂无法支持路径参数, 因此可通过此方式来定义路径参数
	// 但是此处定义的路由不应该包含查询参数
	// 路径参数以:开头, 查询参数以?开头
	Path() map[string]string
}

GroupRouter 结构体路由组定义 用法:首先实现此接口,然后通过调用 Wrapper.IncludeRoute 方法进行注册绑定

type GroupRouterMeta added in v0.2.0

type GroupRouterMeta struct {
	// contains filtered or unexported fields
}

GroupRouterMeta 反射构建路由组的元信息

func NewGroupRouteMeta added in v0.2.0

func NewGroupRouteMeta(router GroupRouter, errorFormatter RouteErrorFormatter) *GroupRouterMeta

NewGroupRouteMeta 构建一个路由组的主入口

func (*GroupRouterMeta) Init added in v0.2.0

func (r *GroupRouterMeta) Init() (err error)

func (*GroupRouterMeta) Routes added in v0.2.0

func (r *GroupRouterMeta) Routes() []*GroupRoute

func (*GroupRouterMeta) Scan added in v0.2.0

func (r *GroupRouterMeta) Scan() (err error)

func (*GroupRouterMeta) ScanInner added in v0.2.0

func (r *GroupRouterMeta) ScanInner() (err error)

ScanInner 处理内部路由 GroupRoute 的文档等数据

func (*GroupRouterMeta) String added in v0.2.0

func (r *GroupRouterMeta) String() string

type H

type H = map[string]any // gin.H

type IndexFinder added in v0.2.0

type IndexFinder[T RouteIface] struct {
	// contains filtered or unexported fields
}

func (*IndexFinder[T]) Get added in v0.2.0

func (f *IndexFinder[T]) Get(id string) (T, bool)

func (*IndexFinder[T]) Init added in v0.2.0

func (f *IndexFinder[T]) Init(items []T)

func (*IndexFinder[T]) Range added in v0.2.0

func (f *IndexFinder[T]) Range(fn func(item T) bool)

Range if false returned, for-loop will stop

type IntModelBinder added in v0.3.1

type IntModelBinder[T constraints.Signed | ~string] struct {
	Maximum int64 `json:"maximum,omitempty"`
	Minimum int64 `json:"minimum,omitempty"`
	// contains filtered or unexported fields
}

IntModelBinder 有符号数字验证

func (*IntModelBinder[T]) ModelName added in v0.3.1

func (m *IntModelBinder[T]) ModelName() string

func (*IntModelBinder[T]) Name added in v0.3.1

func (m *IntModelBinder[T]) Name() string

func (*IntModelBinder[T]) RouteParamType added in v0.3.1

func (m *IntModelBinder[T]) RouteParamType() openapi.RouteParamType

func (*IntModelBinder[T]) Validate added in v0.3.1

func (m *IntModelBinder[T]) Validate(c *Context, requestParam any) (any, []*openapi.ValidationError)

Validate 验证并转换数据类型 如果是string类型,则按照定义进行转换,反之则直接返回

type JsonModelBinder added in v0.3.1

type JsonModelBinder[T any] struct {
	// contains filtered or unexported fields
}

JsonModelBinder json数据类型验证器,适用于泛型路由

func (*JsonModelBinder[T]) ModelName added in v0.3.1

func (m *JsonModelBinder[T]) ModelName() string

func (*JsonModelBinder[T]) Name added in v0.3.1

func (m *JsonModelBinder[T]) Name() string

func (*JsonModelBinder[T]) RouteParamType added in v0.3.1

func (m *JsonModelBinder[T]) RouteParamType() openapi.RouteParamType

func (*JsonModelBinder[T]) Validate added in v0.3.1

func (m *JsonModelBinder[T]) Validate(c *Context, requestParam any) (any, []*openapi.ValidationError)

type LoggerIface added in v0.2.0

type LoggerIface interface {
	Debug(args ...any)
	Info(args ...any)
	Warn(args ...any)
	Error(args ...any)
	Errorf(format string, args ...any)
	Warnf(format string, args ...any)
	Debugf(format string, args ...any)
}

LoggerIface 自定义logger接口,log及zap等均已实现此接口

type ModelBinder added in v0.3.1

type ModelBinder interface {
	Name() string                           // 名称,用来区分不同实现
	ModelName() string                      // 需要校验的模型名称,用于在校验未通过时生成错误信息
	RouteParamType() openapi.RouteParamType // 参数类型
	// Validate 校验方法
	// 对于响应体首先校验,然后再 Marshal;对于请求,首先 Unmarshal 然后再校验
	// 对于不需要 Context 参数的校验方法可默认设置为nil
	// requestParam 为需要验证的数据模型,如果验证通过,则第一个返回值为做了类型转换的 requestParam
	Validate(c *Context, requestParam any) (any, []*openapi.ValidationError)
}

ModelBinder 参数模型校验

type MuxContext added in v0.2.0

type MuxContext interface {
	Method() string // [重要方法]获得当前请求方法,取值为 http.MethodGet, http.MethodPost 等
	Path() string   // [重要方法]获的当前请求的路由模式,而非请求Url

	Ctx() any                                // 原始的 Context
	Set(key string, value any)               // Set用于存储专门用于此上下文的新键/值对,如果以前没有使用c.Keys,它也会延迟初始化它
	Get(key string) (value any, exists bool) // 从上下文中读取键/值对

	ClientIP() string                              // 获得客户端IP
	ContentType() string                           // 请求体的 Content-Type
	GetHeader(key string) string                   // 读取请求头
	Cookie(name string) (string, error)            // 读取cookie
	Params(key string, undefined ...string) string // 读取路径参数
	Query(key string, undefined ...string) string  // 读取查询参数
	MultipartForm() (*multipart.Form, error)       // 读取 multipart/form-data 数据
	// ShouldBind 绑定请求体到obj上,如果已完成数据校验则返回true,error 应为validator.ValidationErrors 类型
	ShouldBind(obj any) (validated bool, err error)

	Header(key, value string)                       // 添加响应头 [!!注意是添加响应头,而非读取]
	SetCookie(cookie *http.Cookie)                  // 添加cookie
	Redirect(code int, location string) error       // 重定向
	Status(code int)                                // 设置响应状态码
	SendString(s string) error                      // 写字符串到响应体,当此方法执行完毕时应中断后续流程
	JSON(code int, data any) error                  // 写入json响应体
	SendStream(stream io.Reader, size ...int) error // 写入消息流到响应体
	File(filepath string) error                     // 返回文件
	FileAttachment(filepath, filename string) error // 将指定的文件以有效的方式写入主体流, 在客户端,文件通常会以给定的文件名下载
	Write(p []byte) (int, error)                    // 写入响应字节流,当此方法执行完毕时应中断后续流程
}

MuxContext Web引擎的 Context,例如 fiber.Ctx, gin.Context 此接口定义的方法无需全部实现

  1. Method 和 Path 方法必须实现且不可返回空值,否则将导致 panic
  2. 对于 MuxContext 缺少的方法,可通过直接调用 Ctx 来实现
  3. 对于 Set / Get 方法,如果实际的Context未提供,则通过 Context.Get/Context.Set 代替
  4. GetHeader, Cookie, Query, Params 是必须实现的方法
  5. ShouldBind 和 BodyParser + Validate 必须实现一个,如果请求体不是JSON时则重写此方法,同时 CustomShouldBindMethod 需要返回 true

type MuxHandler added in v0.2.0

type MuxHandler func(c MuxContext) error

type MuxWrapper added in v0.2.0

type MuxWrapper interface {
	// Listen 启动http server
	Listen(addr string) error
	// ShutdownWithTimeout 优雅关闭
	ShutdownWithTimeout(timeout time.Duration) error
	// BindRoute 注册路由
	BindRoute(method, path string, handler MuxHandler) error
}

MuxWrapper WEB服务器包装器接口 为兼容不同的 server 引擎,需要对其二次包装

type None added in v0.2.6

type None struct{}

None 可用于POST/PATH/PUT方法的占位

func (*None) SchemaDesc added in v0.2.6

func (*None) SchemaDesc() string

type NothingModelBinder added in v0.3.1

type NothingModelBinder struct {
	// contains filtered or unexported fields
}

NothingModelBinder 空实现,用于什么也不做

func NewNothingModelBinder added in v0.3.1

func NewNothingModelBinder(model openapi.SchemaIface, paramType openapi.RouteParamType) *NothingModelBinder

func (*NothingModelBinder) ModelName added in v0.3.1

func (m *NothingModelBinder) ModelName() string

ModelName 该字段可以为空字符串

func (*NothingModelBinder) Name added in v0.3.1

func (m *NothingModelBinder) Name() string

func (*NothingModelBinder) RouteParamType added in v0.3.1

func (m *NothingModelBinder) RouteParamType() openapi.RouteParamType

func (*NothingModelBinder) Validate added in v0.3.1

func (m *NothingModelBinder) Validate(c *Context, requestParam any) (any, []*openapi.ValidationError)

type QueryParamMode added in v0.2.0

type QueryParamMode string

QueryParamMode 查询参数的定义模式,不同模式决定了查询参数的校验方式 对于泛型路由来说,仅存在 结构体查询参数 StructQueryParamMode 一种形式; 对于路由组路由来说,三种形式都存在

const (
	// NoQueryParamMode 不存在查询参数 = 0
	NoQueryParamMode QueryParamMode = "NoQueryParamMode"
	// Deprecated:SimpleQueryParamMode 只有基本数据类型的简单查询参数类型,不包含结构体类型的查询参数 = 1
	SimpleQueryParamMode QueryParamMode = "SimpleQueryParamMode"
	// StructQueryParamMode 以结构体形式定义的查询参数模式 = 4
	StructQueryParamMode QueryParamMode = "StructQueryParamMode"
	// Deprecated:MixQueryParamMode 二种形式都有的混合模式 = 7
	MixQueryParamMode QueryParamMode = "MixQueryParamMode"
)

type RequestModelBinder added in v0.3.1

type RequestModelBinder struct {
	// contains filtered or unexported fields
}

func (*RequestModelBinder) ModelName added in v0.3.1

func (m *RequestModelBinder) ModelName() string

func (*RequestModelBinder) Name added in v0.3.1

func (m *RequestModelBinder) Name() string

func (*RequestModelBinder) RouteParamType added in v0.3.1

func (m *RequestModelBinder) RouteParamType() openapi.RouteParamType

func (*RequestModelBinder) Validate added in v0.3.1

func (m *RequestModelBinder) Validate(c *Context, requestParam any) (any, []*openapi.ValidationError)

type Response

type Response struct {
	StatusCode int
	Content    any
}

Response 路由返回值 也用于内部直接传递数据,对于 GroupRouteHandler 不应将其作为函数返回值

func AcquireResponse added in v0.2.0

func AcquireResponse() *Response

type RouteErrorFormatter added in v0.2.6

type RouteErrorFormatter func(c *Context, err error) (statusCode int, resp any)

RouteErrorFormatter 路由函数返回错误时的处理函数,可用于格式化错误信息后返回给客户端

程序启动时会主动调用此方法用于生成openApi文档,所以此函数不应返回 map等类型,否则将无法生成openApi文档

当路由函数返回错误时,会调用此函数,返回值会作为响应码和响应内容, 返回值仅限于可以JSON序列化的消息体
默认情况下,错误码为500,错误信息会作为字符串直接返回给客户端

type RouteErrorOpt added in v0.2.8

type RouteErrorOpt struct {
	StatusCode   int                 `json:"statusCode" validate:"required" description:"请求错误时的状态码"`
	Description  string              `json:"description,omitempty" description:"错误文档"`
	ContentType  openapi.ContentType `json:"contentType" validate:"required" description:"请求错误时的内容类型"`
	ResponseMode any                 `json:"responseMode" validate:"required" description:"请求错误时的响应体,空则为字符串"`
}

RouteErrorOpt 错误处理函数选项, 用于在 SetRouteErrorFormatter 方法里同时设置错误码和响应内容等内容

type RouteIface added in v0.2.0

type RouteIface interface {
	Scanner
	Id() string
	RouteType() RouteType
	Swagger() *openapi.RouteSwagger           // 路由文档
	QueryBinders() []ModelBinder              // 查询参数的处理接口(查询参数名:处理接口),每一个查询参数都必须绑定一个 ParamBinder
	RequestBinders() ModelBinder              // 请求体的处理接口,请求体也只有一个,内部已处理文件+表单
	ResponseBinder() ModelBinder              // 响应体的处理接口,响应体只有一个
	NewInParams(ctx *Context) []reflect.Value // 创建一个完整的函数入参实例列表, 此方法会在完成请求参数校验之后执行
	NewStructQuery() any                      // 创建一个结构体查询参数实例,对于POST/PATCH/PUT, 即为 NewInParams 的最后一个元素; 对于GET/DELETE则为nil
	NewRequestModel() any                     // 创建一个请求体实例,对于POST/PATCH/PUT, 即为 NewInParams 的最后一个元素; 对于GET/DELETE则为nil
	HasStructQuery() bool                     // 是否存在结构体查询参数,如果存在则会调用 NewStructQuery 获得结构体实例
	HasFileRequest() bool                     // 是否存在上传文件
	Call(in []reflect.Value) []reflect.Value  // 调用API
}

RouteIface 路由定义 路由组接口定义或泛型接口定义都需实现此接口

type RouteType added in v0.2.0

type RouteType string
const (
	RouteTypeGroup   RouteType = "GroupRoute"
	RouteTypeGeneric RouteType = "GenericRouteMeta"
)

type ScanHelper added in v0.2.0

type ScanHelper struct{}

func (ScanHelper) InferBaseQueryParam added in v0.2.0

func (s ScanHelper) InferBaseQueryParam(param *openapi.RouteParam, routeType RouteType) *openapi.QModel

InferBaseQueryParam 推断基本类型的查询参数

func (ScanHelper) InferObjectQueryParam added in v0.2.0

func (s ScanHelper) InferObjectQueryParam(param *openapi.RouteParam) []*openapi.QModel

InferObjectQueryParam 推断结构体类型的查询参数

func (ScanHelper) InferParamBinder added in v0.3.1

func (s ScanHelper) InferParamBinder(param openapi.SchemaIface, prototypeKind reflect.Kind, paramType openapi.RouteParamType) ModelBinder

InferParamBinder 利用反射推断查询参数、路径参数、cookies参数等的校验器 !!!!! 不能推断请求体参数 !!!!! !!!!! 不能推断响应体参数 !!!!!

func (ScanHelper) InferQueryBinder added in v0.2.0

func (s ScanHelper) InferQueryBinder(qmodel *openapi.QModel, routeType RouteType) ModelBinder

func (ScanHelper) InferResponseBinder added in v0.2.0

func (s ScanHelper) InferResponseBinder(model *openapi.BaseModelMeta, routeType RouteType) ModelBinder

InferResponseBinder 推断响应体的校验器, 当返回值为

基本数据类型时,	binder=NothingModelBinder
struct 时,		binder=JsonModelBinder
FileResponse 时,binder=NothingModelBinder

func (ScanHelper) InferTimeParam added in v0.2.0

func (s ScanHelper) InferTimeParam(param *openapi.RouteParam) (*openapi.QModel, bool)

type Scanner added in v0.2.0

type Scanner interface {
	Init() (err error)      // 初始化元数据对象
	Scan() (err error)      // 扫描并初始化自己
	ScanInner() (err error) // 扫描并初始化自己包含的字节点,通过 child.Init() 实现
}

Scanner 元数据接口 Init -> Scan -> ScanInner -> Init 级联初始化

type SimpleFinder added in v0.2.0

type SimpleFinder[T RouteIface] struct {
	// contains filtered or unexported fields
}

func (*SimpleFinder[T]) Get added in v0.2.0

func (s *SimpleFinder[T]) Get(id string) (T, bool)

func (*SimpleFinder[T]) Init added in v0.2.0

func (s *SimpleFinder[T]) Init(items []T)

func (*SimpleFinder[T]) Range added in v0.2.0

func (s *SimpleFinder[T]) Range(fn func(item T) bool)

Range if false returned, for-loop will stop

type StructQueryBind added in v0.2.0

type StructQueryBind struct {
	// contains filtered or unexported fields
}

StructQueryBind 结构体查询参数验证器

func (*StructQueryBind) Bind added in v0.2.0

func (m *StructQueryBind) Bind(params map[string]any, obj any) []*openapi.ValidationError

func (*StructQueryBind) Unmarshal added in v0.2.0

func (m *StructQueryBind) Unmarshal(params map[string]any, obj any) *openapi.ValidationError

Unmarshal todo 性能损耗过大了

func (*StructQueryBind) Validate added in v0.2.0

func (m *StructQueryBind) Validate(obj any) []*openapi.ValidationError

type TimeModelBinder added in v0.3.1

type TimeModelBinder struct {
	// contains filtered or unexported fields
}

TimeModelBinder 时间校验方法

func (*TimeModelBinder) ModelName added in v0.3.1

func (m *TimeModelBinder) ModelName() string

func (*TimeModelBinder) Name added in v0.3.1

func (m *TimeModelBinder) Name() string

func (*TimeModelBinder) RouteParamType added in v0.3.1

func (m *TimeModelBinder) RouteParamType() openapi.RouteParamType

func (*TimeModelBinder) Validate added in v0.3.1

func (m *TimeModelBinder) Validate(c *Context, requestParam any) (any, []*openapi.ValidationError)

Validate 验证一个字符串是否是一个有效的时间字符串 @return time.Time

type UintModelBinder added in v0.3.1

type UintModelBinder[T constraints.Unsigned | ~string] struct {
	Maximum uint64 `json:"maximum,omitempty"`
	Minimum uint64 `json:"minimum,omitempty"`
	// contains filtered or unexported fields
}

UintModelBinder 无符号数字验证

func (*UintModelBinder[T]) ModelName added in v0.3.1

func (m *UintModelBinder[T]) ModelName() string

func (*UintModelBinder[T]) Name added in v0.3.1

func (m *UintModelBinder[T]) Name() string

func (*UintModelBinder[T]) RouteParamType added in v0.3.1

func (m *UintModelBinder[T]) RouteParamType() openapi.RouteParamType

func (*UintModelBinder[T]) Validate added in v0.3.1

func (m *UintModelBinder[T]) Validate(c *Context, requestParam any) (any, []*openapi.ValidationError)

Validate 验证并转换数据类型 如果是string类型,则按照定义进行转换,反之则直接返回

type Wrapper added in v0.2.0

type Wrapper struct {
	// contains filtered or unexported fields
}

Wrapper 服务对象,本质是一个包装器

# usage
./test/group_router_test.go

func Default added in v0.3.1

func Default(c ...Config) *Wrapper

Default 创建应用,多次调用获取同一个对象

func New

func New(c Config) *Wrapper

New 创建一个新的 Wrapper 服务 其存在目的在于在同一个应用里创建多个 Wrapper 实例,并允许每个实例绑定不同的服务器实现

func (*Wrapper) Config added in v0.2.0

func (f *Wrapper) Config() *Config

func (*Wrapper) Context added in v0.2.3

func (f *Wrapper) Context() context.Context

Context Wrapper根 context

func (*Wrapper) DisableResponseValidate added in v0.3.1

func (f *Wrapper) DisableResponseValidate() *Wrapper

DisableResponseValidate 禁用响应参数校验, 仅JSON类型有效

func (*Wrapper) DisableSwagAutoCreate added in v0.2.0

func (f *Wrapper) DisableSwagAutoCreate() *Wrapper

DisableSwagAutoCreate 禁用文档自动生成

func (*Wrapper) Done added in v0.2.0

func (f *Wrapper) Done() <-chan struct{}

Done 监听程序是否退出或正在关闭,仅当程序关闭时解除阻塞

func (*Wrapper) Handler added in v0.2.0

func (f *Wrapper) Handler(ctx MuxContext) error

Handler 路由函数 MuxHandler,实现逻辑类似于装饰器

路由处理方法(装饰器实现),用于请求体校验和返回体序列化,同时注入全局服务依赖, 此方法接收一个业务层面的路由钩子方法 RouteIface.Call

方法首先会查找路由元信息,如果找不到则直接跳过验证环节,由路由器返回404 反之:

  1. 申请一个 Context, 并初始化请求体、路由参数等
  2. 之后会校验并绑定路由参数(包含路径参数和查询参数)是否正确,如果错误则直接返回422错误,反之会继续序列化并绑定请求体(如果存在)序列化成功之后会校验请求参数的正确性,
  3. 校验通过后会调用 RouteIface.Call 并将返回值绑定在 Context 内的 Response 上
  4. 校验返回值,并返回422或将返回值写入到实际的 response

func (*Wrapper) IncludeRouter added in v0.2.0

func (f *Wrapper) IncludeRouter(router GroupRouter) *Wrapper

IncludeRouter 注册一个路由组

func (*Wrapper) Mux added in v0.2.0

func (f *Wrapper) Mux() MuxWrapper

Mux 获取路由器

func (*Wrapper) OnEvent added in v0.2.0

func (f *Wrapper) OnEvent(kind EventKind, fc func()) *Wrapper

OnEvent 添加事件

func (*Wrapper) Run added in v0.2.0

func (f *Wrapper) Run(host, port string)

Run 启动服务, 此方法会阻塞运行,因此必须放在main函数结尾 此方法已设置关闭事件和平滑关闭. 当 Interrupt 信号被触发时,首先会关闭 根Context,然后逐步执行“关机事件”,最后调用平滑关闭方法,关闭服务 启动前通过 SetShutdownTimeout 设置"平滑关闭异常时"的最大超时时间

func (*Wrapper) SetDescription added in v0.2.0

func (f *Wrapper) SetDescription(description string) *Wrapper

SetDescription 设置APP的详细描述信息

func (*Wrapper) SetMux added in v0.2.0

func (f *Wrapper) SetMux(mux MuxWrapper) *Wrapper

SetMux 设置路由器,必须在启动之前设置

func (*Wrapper) SetRouteErrorFormatter added in v0.2.6

func (f *Wrapper) SetRouteErrorFormatter(handle RouteErrorFormatter, opt ...RouteErrorOpt) *Wrapper

SetRouteErrorFormatter 设置路由错误信息格式化函数 @param handle RouteErrorFormatter 路由错误信息格式化函数 @param opt RouteErrorOpt 路由错误信息的配置项, 仅用于设置文档显示

func (*Wrapper) SetShutdownTimeout added in v0.2.0

func (f *Wrapper) SetShutdownTimeout(timeout int) *Wrapper

SetShutdownTimeout 修改关机前最大等待时间

@param	timeout	in	修改关机前最大等待时间,	单位秒

func (*Wrapper) Shutdown added in v0.2.0

func (f *Wrapper) Shutdown()

Shutdown 平滑关闭

func (*Wrapper) Use added in v0.2.0

func (f *Wrapper) Use(hooks ...DependenceHandle) *Wrapper

Use 添加一个依赖函数(锚点), 数据校验后依赖函数

由于 Wrapper 的核心实现类似于装饰器, 而非常规的中间件,因此无法通过 MuxWrapper 的中间件来影响到 Wrapper 的执行过程; 因此 Wrapper 在关键环节均定义了相关的依赖函数,类似于hook,以此来控制执行流程;

与python-FastApi的Depends不同的地方在于:
	python-FastApi.Depends接收Request作为入参,并将其返回值作为路由函数Handler的入参;
	而此处的hook不返回值,而是通过 Context.Set 和 Context.Get 来进行上下文数据的传递,并通过返回 error 来终止后续的流程;
	同时,由于 Context.Set 和 Context.Get 是线程安全的,因此可以放心的在依赖函数中操作 Context;
   	依赖函数的执行始终是顺序进行的,其执行顺序是固定的:
   	始终由 UsePrevious -> (请求参数)Validate -> UseAfter -> (路由函数)RouteHandler -> (响应参数)Validate -> UseBeforeWrite -> exit;

此处的依赖函数有校验前依赖函数和校验后依赖函数,分别通过 Wrapper.UsePrevious 和 Wrapper.UseAfter 注册; 当请求参数校验失败时不会执行 Wrapper.UseAfter 依赖函数, 请求参数会在 Wrapper.UsePrevious 执行完成之后被触发; 如果依赖函数要终止后续的流程,应返回 error, 错误消息会作为消息体返回给客户端, 响应数据格式默认为500+string,可通过 Wrapper.SetRouteErrorFormatter 进行修改;

func (*Wrapper) UseAfter added in v0.2.0

func (f *Wrapper) UseAfter(hooks ...DependenceHandle) *Wrapper

UseAfter 添加一个校验后依赖函数(也即路由前), 此依赖函数会在:请求参数校验后-路由函数调用前执行

func (*Wrapper) UseBeforeWrite added in v0.2.2

func (f *Wrapper) UseBeforeWrite(fc func(c *Context)) *Wrapper

UseBeforeWrite 在数据写入响应流之前执行的钩子方法; 可用于日志记录, 所有请求无论何时终止都会执行此方法

func (*Wrapper) UseDepends deprecated added in v0.2.4

func (f *Wrapper) UseDepends(hooks ...DependenceHandle) *Wrapper

Deprecated:UseDepends 【别名】添加一个数据校验后依赖函数

func (*Wrapper) UsePrevious added in v0.2.0

func (f *Wrapper) UsePrevious(hooks ...DependenceHandle) *Wrapper

UsePrevious 添加一个校验前依赖函数,此依赖函数会在:请求参数校验前调用

Directories

Path Synopsis
middleware
Code generated by go-bindata.
Code generated by go-bindata.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL