Documentation ¶
Overview ¶
webapi 包定义一组抽象过程与辅助类型,用于开发特定协议的 WebAPI 框架,如 SlimAPI 。
Index ¶
- Constants
- func CreateHandlerFunc(handler ApiHandler, logFinder logx.LogFinder) http.HandlerFunc
- func DescribeError(err error) (logLevel logx.Level, errTypeName, errDescription string)
- func GetRouteParam(r *http.Request, name string) string
- func PanicApiError(state *ApiState, cause error, message string, args ...interface{})
- func SetRouteParams(r *http.Request, params map[string]string) *http.Request
- type ApiDecoder
- type ApiEngine
- type ApiError
- type ApiHandler
- type ApiHandlerWrapper
- type ApiLogger
- type ApiMethod
- type ApiMethodArgDecodeFunc
- type ApiMethodCaller
- type ApiMethodRegister
- type ApiNameResolver
- type ApiResponse
- type ApiResponseBuilder
- type ApiResponseWriter
- type ApiSetup
- type ApiState
- type ApiUserHostResolver
- type BadRequestError
- type QueryString
Constants ¶
const ( // ContentTypeNone 未指定类型。 ContentTypeNone = "" // ContentTypeJson 对应 Content-Type: application/json 的值。 ContentTypeJson = "application/json" // ContentTypeBinary 对应 Content-Type: application/octet-stream 的值。 ContentTypeBinary = "application/octet-stream" // ContentTypeJavascript 对应 Content-Type: text/javascript 的值。 ContentTypeJavascript = "text/javascript" // ContentTypePlainText 对应 Content-Type: text/javascript 的值。 ContentTypePlainText = "text/plain" // ContentTypeForm 对应 Content-Type: application/x-www-form-urlencoded 的值。 ContentTypeForm = "application/x-www-form-urlencoded" // ContentTypeMultipartForm 对应 Content-Type: multipart/form-data 的值。 ContentTypeMultipartForm = "multipart/form-data" )
const ( // 错误码。表示不合规的请求数据。 ErrorCodeBadRequest = 400 // 错误码。表示发生内部错误。 ErrorCodeInternalError = 500 )
用于 WebAPI 预定义的状态码。1000以下基本抄 HTTP 状态码。
const (
// HttpHeaderContentType 对应 HTTP 头中的 Content-Type 字段。
HttpHeaderContentType = "Content-Type"
)
Variables ¶
This section is empty.
Functions ¶
func CreateHandlerFunc ¶
func CreateHandlerFunc(handler ApiHandler, logFinder logx.LogFinder) http.HandlerFunc
CreateHandlerFunc 返回一个封装了给定的 ApiHandler 的 http.HandlerFunc 。
logFinder 用于获取 Logger ,该 Logger 会赋值给 ApiState.Logger 。可为 nil 表示不记录日志。 对于每个请求,其日志名称基于响应该请求的方法,由两部分构成,格式为“{ApiHandler.Name()}.{ApiMethod.Provider}.{ApiMethod.Name}”。 如果未能检索到对应的方法,则日志名称为 ApiHandler.Name() 。
func DescribeError ¶
DescribeError 根据给定的错误,返回错误的日志级别、名称和错误描述。 如果 err 为 nil ,返回 logx.LevelInfo 和空字符串。 此方法可用于搭配 ApiLogger.Log() 输出带有错误描述的日志。
描述信息使用 common.Errors.Describe() 获取。
func GetRouteParam ¶
GetRouteParam 从给定的请求中获取指定名称的路由参数。参数不存在时,返回空字符串。
func PanicApiError ¶
PanicApiError 使用 CreateApiError 创建 ApiError ,并直接直接 panic 。 当 ApiHandler 遇见不应该发生(如编码 bug)的异常情况时,可使用此方法中断处理过程。
Types ¶
type ApiDecoder ¶
type ApiDecoder interface { // Decode 从 HTTP 请求中,构建用于调用 ApiState.Method 的参数,并填入 ApiState.Args 。 // 若参数转换失败,填写 ApiState.Error ,将跳过 ApiMethodCaller 的执行。 Decode(state *ApiState) }
ApiDecoder 用于构建调用方法的参数表。
func NewUniqueTypeApiMethodDecoder ¶ added in v0.2.0
func NewUniqueTypeApiMethodDecoder(decodeFuncs ...ApiMethodArgDecodeFunc) ApiDecoder
NewUniqueTypeApiMethodDecoder 返回一个 ApiDecoder 的实现。此实现要求被调用的每个方法,其参数表中的参数类型是不重复的。 可通过此方法组装解析过程,进而实现一个 ApiDecoder 。
decodeFuncs 给定各种类型参数的解析过程。它形成一个管道,当一个 API 方法被调用时,每个参数依次通过此管道中的每个函数, 当首次遇到返回 ok=true 时,参数取用该过程的值。
管道中的第一个元素是预定义的,其用于解析 *webapi.ApiState 并赋值。 decodeFuncs 会追加此过程后面。
type ApiEngine ¶
type ApiEngine struct {
// contains filtered or unexported fields
}
ApiEngine 是一个 http.Handler 。表示一个抽象的 HTTP 服务器,基于 ApiHandler 注册和管理 WebAPI 。
func (*ApiEngine) Handle ¶
func (engine *ApiEngine) Handle(path string, handler ApiHandler, logFinder logx.LogFinder) ApiSetup
Handle 指定一个 ApiHandler ,响应对应 URL 路径下的请求。 通过 CreateHandlerFunc(handler, logFinder) 方法创建用于响应请求的过程。 返回 ApiSetup ,用于向 ApiHandler 注册 API 方法。
path 为相对路径,以 / 开头。参考 https://github.com/go-chi/chi
type ApiError ¶
type ApiError struct {
// contains filtered or unexported fields
}
ApiError 用于表示 ApiHandler 处理过程中的内部错误,这些错误通常表示代码存在问题(如编码 bug)。 这些问题不能在程序生命周期中自动解决,通常使用 panic 中断程序。
func CreateApiError ¶
CreateApiError 创建一个 ApiError 。 message 和 args 指定描述信息,使用 fmt.Sprintf() 格式化。 cause 是引起此错误的错误,可以为 nil 。 message 会体现在 ApiError.Error() ,格式为:
message:: cause.Error()
type ApiHandler ¶
type ApiHandler interface { ApiMethodRegister ApiNameResolver ApiUserHostResolver ApiDecoder ApiMethodCaller ApiResponseBuilder ApiResponseWriter ApiLogger // Name 获取当前 ApiHandler 的标识符。每个 ApiHandler 应具有唯一的名称。 // 名称可以是任意值,包括空字符串。但应尽量给定容易识别的名称。 Name() string // SupportedHttpMethods 返回当前 ApiHandler 支持的 HTTP 方法。如 GET 、 POST 、 PUT 、 DELETE 等。 SupportedHttpMethods() []string }
ApiHandler 定义了 WebAPI 处理过程中的抽象环节。 CreateHandlerFunc() 返回一个函数,基于 ApiHandler 实现完整的处理过程。
其中 ApiNameResolver 、 ApiUserHostResolver 、 ApiDecoder 、 ApiMethodCaller
type ApiHandlerWrapper ¶
type ApiHandlerWrapper struct { ApiMethodRegister ApiNameResolver ApiUserHostResolver ApiDecoder ApiMethodCaller ApiResponseBuilder ApiResponseWriter ApiLogger // HandlerName 是 ApiHandler.Name() 的返回值。 HandlerName string // HttpMethods 是 ApiHandler.SupportedHttpMethods() 的返回值。 HttpMethods []string }
ApiHandlerWrapper 用于组装各个接口,以实现 ApiHandler 。 各种 ApiHandler 的实现中,可使用此类型作为脚手架,组装各个内嵌接口。
func (*ApiHandlerWrapper) Name ¶
func (w *ApiHandlerWrapper) Name() string
Name 实现 ApiHandler.Name() 。
func (*ApiHandlerWrapper) SupportedHttpMethods ¶
func (w *ApiHandlerWrapper) SupportedHttpMethods() []string
SupportedHttpMethods 实现 ApiHandler.SupportedHttpMethods() 。
type ApiLogger ¶
type ApiLogger interface { // Log 根据 ApiState 的内容生成日志,日志由 ApiState.Logger 接收。 // 若 ApiState.Logger 为 nil ,则不生成日志。 Log(state *ApiState) }
ApiLogger 在 ApiResponseWriter.WriteResponse 被调用后,生成日志。
type ApiMethod ¶
type ApiMethod struct { // Name 是注册的 WebAPI 方法的名称。 // 虽然在检索时使用大小写不敏感的方式,但这里通常记录注册时所使用的可区分大小写的名称。 Name string // Value 记录目标方法。 Value reflect.Value // Provider 指定方法提供者的名称,用于对方法加以分类,可为空。 Provider string }
ApiMethod 表示一个通过 ApiMethodRegister 注册的方法。
type ApiMethodArgDecodeFunc ¶ added in v0.2.0
type ApiMethodArgDecodeFunc func(state *ApiState, index int, argType reflect.Type) (ok bool, v interface{}, err error)
ApiMethodArgDecodeFunc 定义一个过程,此过程用于从 ApiState 中解析得到 API 方法的特定参数的值。 一组 ApiMethodArgDecodeFunc 形成一个解析 API 方法中每个参数的管道: 若给定的 API 参数(通过 index 和 argType 识别)可被当前函数解析,则返回 ok=true 及解析结果 v ,或者返回 ok=false 及解析错误; 若当前函数不支持给定参数的解析,则返回无错误的 ok=false 和 v=nil 。
type ApiMethodCaller ¶
type ApiMethodCaller interface { // 使用参数 ApiState.Args 调用 ApiState.Method 所对应的方法,将调用结果填入 ApiState.Data 和 ApiState.Error 。 // 应仅在 ApiState.Error 为 nil 时调用此方法。方法通过 ApiMethodRegister 注册时已完成类型校验。 Call(state *ApiState) }
ApiMethodCaller 用于调用特定的方法。
func NewBasicApiMethodCaller ¶
func NewBasicApiMethodCaller() ApiMethodCaller
NewBasicApiMethodCaller 返回一个预定义的 ApiMethodCaller 的标准实现。 当实现一个 ApiHandler 时,可基于此实例实现 ApiMethodCaller 。
type ApiMethodRegister ¶
type ApiMethodRegister interface { // RegisterMethod 注册一个方法。 // 注册时,对于方法名称应采用大小写不敏感的方式处理。若多次注册同一个名称,最后注册的将之前的覆盖。 // // 允许方法具有0-2个输出参数。 // - 1个参数时,参数可以是任意 struct/map[string]*/基础类型 或者此三类作为元素的 slice ,也可以是 error 。 // - 2个参数时,第一个参数可以是 struct/map[string]*/基础类型 或者此三类作为元素的 slice ,第二个参数必须是 error 。 // RegisterMethod(m ApiMethod) // RegisterMethods 将给定的 struct 上的所有公开方法注册为 WebAPI 。若给定的不是 struct ,则 panic 。 // 通过此方法注册后,通过 GetMethod() 获取的 ApiMethod.Provider 为给定的 struct 的名称,对应 reflect.Type.Name() 的值。 // // 对方法名称使用一组约定(下划线使用名称中的第一个下划线): // - 若方法名称格式为 Method__Name (使用两个下划线分割),则 Name 被注册为 WebAPI 名称; // - 若方法名称格式为 Method__ (使用两个下划线结尾)或 Method____ (两个下划线之后也只有下划线),则此方法不会被注册为 WebAPI ; // - 其余情况,均使用方法的原始名称作为 WebAPI 名称。 // 这里 Method 和 Name 均为可变量, Method 用于指代代码内有意义的方法名称, Name 指代 WebAPI 名称。例如 GetName__13 注册一个名称为 // “13”的 API 方法,其方法业务意义为 GetName 。 // // 每个方法的注册逻辑与 RegisterMethod 一致。 // 特别的,如果格式为 Method____abc ,两个下划线之后存在有效名称,则 WebAPI 名称为 __abc ,从两个下划线后的下一个字符(还是下划线)开始取。 // RegisterMethods(providerStruct interface{}) // GetMethod 返回具有指定名称的方法。若方法存在,返回 ApiMethod 和 true ;若未被注册,返回零值和 false 。 // 对于方法名称应采用大小写不敏感的方式处理。 GetMethod(name string) (method ApiMethod, ok bool) }
ApiMethodRegister 用于向 ApiHandler 中注册 WebAPI 方法。 此过程用于初始化 ApiHandler ,初始化过程应在接收第一个请求前完成,并以单线程方式进行。 注册方法时,应对方法的输入输出类型做合法性校验。
func NewBasicApiMethodRegister ¶
func NewBasicApiMethodRegister() ApiMethodRegister
NewBasicApiMethodRegister 返回一个预定义的 ApiMethodRegister 的标准实现。 当实现一个 ApiHandler 时,可基于此实例实现 ApiMethodRegister 。
type ApiNameResolver ¶
type ApiNameResolver interface { // FillMethod 从当前 HTTP 请求里获取 API 方法的名称,并填入 ApiState.Name ;如果未能解析到名称,则不需要填写。 // 若请求非法,可填写 ApiState.Error ,跳过 ApiDecoder 和 ApiMethodCaller 的执行。 FillMethod(state *ApiState) }
ApiNameResolver 用于从当前 HTTP 请求中,解析得到目标 API 方法的名称。
type ApiResponse ¶
type ApiResponse struct { // 状态码, 0 表示一个成功的请求,其他值表示有错误。 Code int // Message 在 Code 不为 0 时,记录用于描述错误的消息。 Message string // Data 记录返回的数据本体。 Data interface{} }
ApiResponse 用于表示返回的数据。
func SuccessResponse ¶
func SuccessResponse(data interface{}) *ApiResponse
SuccessResponse 返回一个表示成功的 ApiResponse 。
type ApiResponseBuilder ¶
type ApiResponseBuilder interface { // BuildResponse 根据 ApiState.Data 和 ApiState.Error ,填写 ApiState.Response 。 BuildResponse(state *ApiState) }
ApiResponseBuilder 处理 ApiDecoder 和 ApiMethodCaller 执行过程中产生的错误。
func NewBasicApiResponseBuilder ¶
func NewBasicApiResponseBuilder() ApiResponseBuilder
NewBasicApiResponseBuilder 返回一个预定义的 ApiResponseBuilder 的标准实现。 当实现一个 ApiHandler 时,可基于此实例实现 ApiResponseBuilder 。
type ApiResponseWriter ¶
type ApiResponseWriter interface { // 处理 ApiState.Response ,获得实际需要返回的数据,填入 ApiState.Response* (以 Response 开头)字段。 // 此方法执行之后, ApiState 中以 Response 开头字段,如 ResponseBody 、 ResponseContentType , // 均需要完成赋值。 WriteResponse(state *ApiState) }
ApiResponseWriter 处理 ApiMethodCaller 的处理结果,获得实际需要返回的数据,填入 Response* (以 Response 开头)字段。
type ApiSetup ¶
type ApiSetup struct {
// contains filtered or unexported fields
}
ApiSetup 用于向 ApiHandler 注册 API 方法。
func (ApiSetup) RegisterMethods ¶
RegisterMethods 同 ApiMethodRegister.RegisterMethods 。 将给定的 struct 上的所有公开方法注册为 WebAPI 。若给定的不是 struct ,则 panic 。 返回 ApiSetup 实例自身,以便编码形成流式调用。
对方法名称使用一组约定(下划线使用名称中的第一个下划线):
- 若方法名称格式为 Method__Name (使用两个下划线分割),则 Name 被注册为 WebAPI 名称;
- 若方法名称格式为 Method__ (使用两个下划线结尾)或 Method____ (两个下划线之后也只有下划线),则此方法不会被注册为 WebAPI ;
- 其余情况,均使用方法的原始名称作为 WebAPI 名称。
这里 Method 和 Name 均为可变量, Method 用于指代代码内有意义的方法名称, Name 指代 WebAPI 名称。例如 GetName__13 注册一个名称为 “13”的 API 方法,其方法业务意义为 GetName 。
每个方法的注册逻辑与 RegisterMethod 一致。 特别的,如果格式为 Method____abc ,两个下划线之后存在有效名称,则 WebAPI 名称为 __abc ,从两个下划线后的下一个字符(还是下划线)开始取。
type ApiState ¶
type ApiState struct { // RawRequest 是原始的 HTTP 请求。对应 http.Handler 的参数。 RawRequest *http.Request // RawResponse 用于写入 HTTP 回执。对应 http.Handler 的参数。 RawResponse http.ResponseWriter // Query 是按 ASP.net 的方式解析 URL 上的参数。 // 由于通信协议是按 .net 版的方式制定的,获取 query-string 应通过此字段进行。 Query QueryString // Handler 当前的 ApiHandler 。 Handler ApiHandler // Logger 用于接收当前请求的处理流程中需记录的日志。可以为 nil ,表示不记录日志。 // 应在 Method 被调用前,即 ApiMethodCaller.Call() 之前初始化。 Logger logx.Logger // Name 记录调用 WebAPI 给定的方法名称,它应被唯一的映射到一个 Method 。 // ApiNameResolver 接口定义了初始化此字段的方法。 Name string // Method 记录要调用的方法,和 Name 一一映射,可从通过 ApiMethodRegister.GetMethod(ApiState.Name) 得到。 // 方法由 ApiMethodCaller 调用,参数从 Args 获取。 Method ApiMethod // MethodArgs 存放用于调用 Method 的参数。 // ApiDecoder 接口定义了初始化此字段的方法。 Args []reflect.Value // UserHost 记录发起 HTTP 请求的客户端 IP 地址。 // ApiUserHostResolver 接口定义了初始化此字段的方法。 UserHost string // Data 记录 ApiMethodCaller.Call() 方法所调用的具体 WebAPI 方法返回的非 error 值。 // 若方法没有返回值,此字段为 nil 。 Data interface{} // Error 记录 ApiMethodCaller.Call() 方法所调用的具体 WebAPI 方法返回的 error 值; // 或记录 ApiDecoder 和 ApiMethodCaller 处理过程中 panic 的错误。没有错误时为 nil 。 // ApiResponseBuilder.BuildResponse() 能够将此错误转换为对应的 ApiResponse 。 Error error // Response 记录 WebAPI 返回的结果的抽象结构。 Response *ApiResponse // ResponseBody 提供实际返回的 HTTP body 的数据。 ResponseBody io.Reader // ResponseContentType 对应为返回的 HTTP 的 Content-Type 头的值。 ResponseContentType string // contains filtered or unexported fields }
ApiState 用于记录一个请求的处理流程中的数据。每个请求使用一个新的 ApiState 。 处理过程采用管道模式,每个步骤从 ApiState 获取所需数据,并将处理结果写回 ApiState 。 当处理过程结束后,以 Response 开头的字段应被填充。
func NewState ¶
func NewState(r http.ResponseWriter, w *http.Request, handler ApiHandler) *ApiState
NewState 创建一个新的 ApiState ,每个请求应使用一个新的 ApiState 。
func (*ApiState) GetCustomData ¶
GetCustomData 获取具有指定名称的扩展字段。返回一个 bool 值表示字段是否存在。
func (*ApiState) MustHaveMethod ¶
func (s *ApiState) MustHaveMethod()
MustHaveMethod checks the Method field, panics if the field is not initialized or is not a Func.
func (*ApiState) MustHaveName ¶
func (s *ApiState) MustHaveName()
MustHaveName checks the Name field, panics if the field is not initialized.
func (*ApiState) MustHaveResponse ¶
func (s *ApiState) MustHaveResponse()
MustHaveResponse checks the Response field, panics if the field is not initialized.
func (*ApiState) SetCustomData ¶
SetCustomData 设置一个扩展字段,字段的聚义意义由各处理过程自行决定。
type ApiUserHostResolver ¶
type ApiUserHostResolver interface { // FillUserHost 获取发起 HTTP 请求的客户端 IP 地址,并填入 ApiState.UserHost 。 // // HTTP 服务经常通过反向代理访问,可能转好几层,需要通过如 X-Forwarded-For 头获取客户端 IP 。 // FillUserHost(state *ApiState) }
ApiUserHostResolver 用于获取发起 HTTP 请求的客户端 IP 地址。 一个请求可能经过多次代理转发,原始地址通常需要从特定 HTTP 头获取,比如 X-Forwarded-For 。
func NewBasicApiUserHostResolver ¶
func NewBasicApiUserHostResolver() ApiUserHostResolver
NewBasicApiUserHostResolver 返回一个预定义的 ApiUserHostResolver 的标准实现。 当实现一个 ApiHandler 时,可基于此实例实现 ApiUserHostResolver 。
type BadRequestError ¶
type BadRequestError struct {
// contains filtered or unexported fields
}
BadRequestError 记录一个不正确的请求,例如请求的参数不符合要求,请求的 API 方法不存在等。 这些错误是外部请求而不是编码导致(假设没 bug )的, WebAPI 流程应能够正确处理这些错误并返回对应结果。 可以为 BadRequestError 指定一个描述信息,此信息可能作为 WebAPI 的返回值,被请求者看到。
func CreateBadRequestError ¶
func CreateBadRequestError(state *ApiState, cause error, message string, args ...interface{}) BadRequestError
CreateBadRequestError 创建一个 BadRequestError 。 message 和 args 指定其消息,使用 fmt.Sprintf() 格式化。 描述信息可能作为 WebAPI 的返回值,被请求者看到,故可能不应当过多暴露程序细节。更具体的错误可以放在 cause 上。
type QueryString ¶
type QueryString struct { // Nameless 记录没有参数名的参数。如“?a&b=1”中的 “a”。 Nameless string // HasNameless 表示是否有无名称的参数。用于区分 Nameless 是空字符串时,空字符串是否是参数值。 HasNameless bool // Named 记录其余全部有参数名的参数。 // 相同名称的参数出现多个时,会被以逗号拼接起来,如“?a=1&a=2”结果为“a=1,2”; // 所有参数名称都会被转为小写,以便以大小写不敏感的方式匹配参数。 Named map[string]string }
QueryString 模拟 .net Framework 的 HttpRequest.QueryString 。
func ParseQueryString ¶
func ParseQueryString(queryString string) QueryString
ParseQueryString 模拟 .net Framework 的 HttpRequest.QueryString 的解析方式。 给定的 queryString 可以以“?”开头,也可以不带。
在传统ASP.net中,“?a&b”解析为一个名称为 null,值为“a,b”的参数;而 Go 的框架则将其等同于 “?a=&b=” 处理,变成 两个名称分别为 a 、 b 而值为空的参数。这与预定义的 API 协议如 SlimAPI 不符。
此方法用于获取与 .net Framework 相同的解析结果。 如果一个参数出现多次,会被以逗号拼接起来,如“?a=1&a=2”结果为“a=1,2”; 特别的,单一的“?”会得到一个没有参数名称的参数,值为空字符串。
Source Files ¶
Directories ¶
Path | Synopsis |
---|---|
slimapi 包基于 webapi ,实现基于 SlimAPI 协议的开发框架。
|
slimapi 包基于 webapi ,实现基于 SlimAPI 协议的开发框架。 |
webapitest 包提供用于测试 webapi 包的辅助方法。
|
webapitest 包提供用于测试 webapi 包的辅助方法。 |