webapi

package module
v0.8.3 Latest Latest
Warning

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

Go to latest
Published: Mar 12, 2024 License: MIT Imports: 14 Imported by: 1

README

webapi

GoDoc Go codecov License GoVersion Go Report Card

这是SlimWebApi的 Go 版。 SlimAPI 通信协议详见godoc-SlimAPI通信协议

同时,基于 SlimAPI ,提供一套带有签名校验逻辑的扩展 SlimAuth

快速使用

安装:

go get -u github.com/cmstar/go-webapi@latest

上代码:

package main

import (
	"fmt"
	"net/http"
	"time"

	"github.com/cmstar/go-errx"
	"github.com/cmstar/go-logx"
	"github.com/cmstar/go-webapi"
	"github.com/cmstar/go-webapi/slimapi"
)

func main() {
	// 初始化 API 容器。
	slim := slimapi.NewSlimApiHandler("demo")

	// 注册 WebAPI 方法。
	slim.RegisterMethods(Methods{})

	// 初始化日志。 https://github.com/cmstar/go-logx
	logger := logx.NewStdLogger(nil)
	logFinder := logx.NewSingleLoggerLogFinder(logger)

	// 初始化引擎。
	e := webapi.NewEngine()

	// 注册路由,使用 chi 库的语法。 https://github.com/go-chi/chi
	e.Handle("/api/{~method}", slim, logFinder)

	// 启动。
	err := http.ListenAndServe(":15001", e)
	if err != nil {
		logger.Log(logx.LevelFatal, err.Error())
	}
}

// 用于承载 WebAPI 方法。
type Methods struct{}

// 方法必须是 exported ,即大写字母开头的。
func (Methods) Plus(req struct {
	A int // 参数首字母也必须是大写的。
	B int
}) int {
	return req.A + req.B
}

func (Methods) Time() string {
	return time.Now().Format("2006-01-02 15:04")
}

// 参数也可以是 *webapi.ApiState ,可通过其访问到当前请求的上下文。
// 也可以同时搭配 struct 型的参数。
func (Methods) Headers(state *webapi.ApiState, req struct{ NoMeaning bool }) map[string][]string {
	// RawRequest 是标准库中,当前请求的 *http.Request 。
	return state.RawRequest.Header
}

// 支持至多两个返回值,第一个返回值对应输出的 Data 字段;第二个返回值必须是 error 。详见《错误处理》节。
func (Methods) Err(req struct {
	BizErr bool
	Value  string
}) (string, error) {
	if req.BizErr {
		return req.Value, errx.NewBizError(12345, "your message", nil)
	}
	return "", fmt.Errorf("not a biz-error: %v", req.Value)
}

跑起来,现在可以调用 Methods 上的方法了。方法名称和参数都是大小写不敏感的。

GET http://localhost:15001/api/plus?a=11&b=22

=> {
    "Code": 0,
    "Message": "",
    "Data": 33
}

---
# 以 JSON 格式请求。
POST http://localhost:15001/api/plus
Content-Type: application/json

{"a":11, "b":22}

=> {
    "Code": 0,
    "Message": "",
    "Data": 33
}

---
GET http://localhost:15001/api/time

=> {
    "Code": 0,
    "Message": "",
    "Data": "2022-03-06 23:16"
}

---
GET http://localhost:15001/api/headers

=> {
    "Code": 0,
    "Message": "",
    "Data": {
        "Accept": ["text/html,application/xhtml+xml"],
        "Accept-Encoding": ["gzip, deflate, br"],
        "Connection": ["keep-alive"],
        "User-Agent": ["Mozilla/5.0 ..."],
        ...
    }
}

---
# BizError 会以 Code + Message 的方式体现在输出上。
GET http://localhost:15001/api/err?bizErr=1&value=my-value

=> {
    "Code": 12345,
    "Message": "your message",
    "Data": "my-value"
}

---
# 非 BizError 均表现为 internal error 。
GET http://localhost:15001/api/err?bizErr=false&value=my-value

=> {
    "Code": 500,
    "Message": "internal error",
    "Data": ""
}

如果需要接收上传的文件,参考 WIKI 页 上传文件

错误处理

表示 WebAPI 的方法支持0-2个返回值(详见GoDoc)。

当方法返回:

  • 没有 error 返回值或返回的 errornil:表示调用成功,输出的 Code=0
  • 返回 errx.BizError:输出 Code=BizError.Code(), Message=BizError.Message()
  • 返回不是 errx.BizErrorerror:统一输出 Code=500, Message=internal error
  • 方法 panic:统一输出 Code=500, Message=internal error

BizError 的详细说明,参考go-errx库

Documentation

Overview

webapi 包定义一组抽象过程与辅助类型,用于开发特定协议的 WebAPI 框架,如 SlimAPI 。

Index

Constants

View Source
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"
)
View Source
const (
	// HttpHeaderContentType 对应 HTTP 头中的 Content-Type 字段。
	HttpHeaderContentType = "Content-Type"

	// HttpHeaderContentDisposition 对应 HTTP 头中的 Content-Disposition 字段。
	HttpHeaderContentDisposition = "Content-Disposition"
)
View Source
const (
	// 错误码。表示不合规的请求数据。
	ErrorCodeBadRequest = 400

	// 错误码。表示发生内部错误。
	ErrorCodeInternalError = 500
)

用于 WebAPI 预定义的状态码。1000以下基本抄 HTTP 状态码。

Variables

View Source
var ApiStateArgumentDecoder = apiStateArgumentDecoder{}

ApiStateDecodeFunc 是一个 ArgumentDecoder ,它用于解析并赋值 *ApiState

这是一个单例。

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

func DescribeError(err error) (logLevel logx.Level, errTypeName, errDescription string)

DescribeError 根据给定的错误,返回错误的日志级别、名称和错误描述。 如果 err 为 nil ,返回 logx.LevelInfo 和空字符串。 此方法可用于搭配 ApiLogger.Log() 输出带有错误描述的日志。

描述信息使用 common.Errors.Describe() 获取。

func GetRouteParam

func GetRouteParam(r *http.Request, name string) string

GetRouteParam 从给定的请求中获取指定名称的路由参数。参数不存在时,返回空字符串。

func PanicApiError

func PanicApiError(state *ApiState, cause error, message string, args ...any)

PanicApiError 使用 CreateApiError 创建 ApiError ,并直接直接 panic 。 当 ApiHandler 遇见不应该发生(如编码 bug)的异常情况时,可使用此方法中断处理过程。

func SetRouteParams

func SetRouteParams(r *http.Request, params map[string]string) *http.Request

SetRouteParams 向当前请求中添加一组路由参数,返回追加参数后的请求。 若给定参数表为 nil 或不包含元素,则返回原始请求。

Types

type ApiDecoder

type ApiDecoder interface {
	// Decode 从 HTTP 请求中,构建用于调用 ApiState.Method 的参数,并填入 ApiState.Args 。
	// 若参数转换失败,填写 ApiState.Error ,将跳过 ApiMethodCaller 的执行。
	Decode(state *ApiState)
}

ApiDecoder 用于构建调用方法的参数表。

type ApiDecoderFunc added in v0.6.6

type ApiDecoderFunc func(state *ApiState)

ApiDecoderFunc 用于将函数适配到 ApiDecoder

func (ApiDecoderFunc) Decode added in v0.6.6

func (f ApiDecoderFunc) Decode(state *ApiState)

Decode 实现 [ApiDecoder.Decode] 。

type ApiEngine

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

ApiEngine 是一个 http.Handler 。表示一个抽象的 HTTP 服务器,基于 ApiHandler 注册和管理 WebAPI 。

func NewEngine

func NewEngine() *ApiEngine

NewEngine 创建一个 ApiEngine 实例,并完成初始化设置。

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

func (*ApiEngine) HandleConnect added in v0.6.7

func (engine *ApiEngine) HandleConnect(path string, handlerFunc http.HandlerFunc)

HandleConnect 调用 chi.Router.Connect

func (*ApiEngine) HandleDelete added in v0.6.7

func (engine *ApiEngine) HandleDelete(path string, handlerFunc http.HandlerFunc)

HandleDelete 调用 chi.Router.Delete

func (*ApiEngine) HandleGet added in v0.6.7

func (engine *ApiEngine) HandleGet(path string, handlerFunc http.HandlerFunc)

HandleGet 调用 chi.Router.Get

func (*ApiEngine) HandleHead added in v0.6.7

func (engine *ApiEngine) HandleHead(path string, handlerFunc http.HandlerFunc)

HandleHead 调用 chi.Router.Head

func (*ApiEngine) HandleOptions added in v0.6.7

func (engine *ApiEngine) HandleOptions(path string, handlerFunc http.HandlerFunc)

HandleOptions 调用 chi.Router.Options

func (*ApiEngine) HandlePatch added in v0.6.7

func (engine *ApiEngine) HandlePatch(path string, handlerFunc http.HandlerFunc)

HandlePatch 调用 chi.Router.Patch

func (*ApiEngine) HandlePost added in v0.6.7

func (engine *ApiEngine) HandlePost(path string, handlerFunc http.HandlerFunc)

HandlePost 调用 chi.Router.Post

func (*ApiEngine) HandlePut added in v0.6.7

func (engine *ApiEngine) HandlePut(path string, handlerFunc http.HandlerFunc)

HandlePut 调用 chi.Router.Put

func (*ApiEngine) HandleTrace added in v0.6.7

func (engine *ApiEngine) HandleTrace(path string, handlerFunc http.HandlerFunc)

HandleTrace 调用 chi.Router.Trace

func (*ApiEngine) ServeHTTP

func (engine *ApiEngine) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP implements http.Handler.ServeHTTP().

type ApiError

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

ApiError 用于表示 ApiHandler 处理过程中的内部错误,这些错误通常表示代码存在问题(如编码 bug)。 这些问题不能在程序生命周期中自动解决,通常使用 panic 中断程序。

func CreateApiError

func CreateApiError(state *ApiState, cause error, message string, args ...any) ApiError

CreateApiError 创建一个 ApiError 。 message 和 args 指定描述信息,使用 fmt.Sprintf() 格式化。 cause 是引起此错误的错误,可以为 nil 。 message 会体现在 ApiError.Error() ,格式为:

message:: cause.Error()

func (ApiError) Error

func (e ApiError) Error() string

Error 实现 error 接口。

type ApiHandler

type ApiHandler interface {
	ApiMethodRegister
	ApiUserHostResolver
	ApiNameResolver
	ApiDecoder
	ApiMethodCaller
	ApiResponseBuilder
	ApiResponseWriter
	ApiLogger

	// Name 获取当前 ApiHandler 的标识符。每个 ApiHandler 应具有唯一的名称。
	// 名称可以是任意值,包括空字符串。但应尽量给定容易识别的名称。
	Name() string

	// SupportedHttpMethods 返回当前 ApiHandler 支持的 HTTP 方法。
	// 如 GET 、 POST 、 PUT 、 DELETE 等,大小写不敏感。
	SupportedHttpMethods() []string
}

ApiHandler 定义了 WebAPI 处理过程中的抽象环节。 CreateHandlerFunc() 返回一个函数,基于 ApiHandler 实现完整的处理过程。

在响应请求时,各接口的执行顺序为:

  • ApiUserHostResolver
  • ApiNameResolver
  • ApiDecoder
  • ApiMethodCaller
  • ApiResponseBuilder
  • ApiResponseWriter
  • ApiLogger

ApiMethodRegister 仅在注册阶段使用,在响应请求的过程中不会被调用。

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 Wrap added in v0.8.1

Wrap 将一个 ApiHandler 包装为 *ApiHandlerWrapper ,用于“重写”其中的方法。

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 ApiLoggerFunc added in v0.6.6

type ApiLoggerFunc func(state *ApiState)

ApiLoggerFunc 用于将函数适配到 ApiLogger

func (ApiLoggerFunc) Log added in v0.6.6

func (f ApiLoggerFunc) Log(state *ApiState)

Log 实现 [ApiLogger.Log] 。

type ApiMethod

type ApiMethod struct {
	// Name 是注册的 WebAPI 方法的名称。
	// 虽然在检索时使用大小写不敏感的方式,但这里通常记录注册时所使用的可区分大小写的名称。
	Name string

	// Value 记录目标方法。
	Value reflect.Value

	// Provider 指定方法提供者的名称,用于对方法加以分类,可为空。
	Provider string
}

ApiMethod 表示一个通过 ApiMethodRegister 注册的方法。

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 ApiMethodCallerFunc added in v0.6.6

type ApiMethodCallerFunc func(state *ApiState)

ApiMethodCallerFunc 用于将函数适配到 ApiMethodCaller

func (ApiMethodCallerFunc) Call added in v0.6.6

func (f ApiMethodCallerFunc) Call(state *ApiState)

Call 实现 [ApiMethodCaller.Call] 。

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 any)

	// 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 ApiNameResolverFunc added in v0.6.6

type ApiNameResolverFunc func(state *ApiState)

ApiNameResolverFunc 用于将函数适配到 ApiNameResolver

func (ApiNameResolverFunc) FillMethod added in v0.6.6

func (f ApiNameResolverFunc) FillMethod(state *ApiState)

FillMethod 实现 [ApiNameResolver.FillMethod] 。

type ApiResponse

type ApiResponse[T any] struct {
	// 状态码, 0 表示一个成功的请求,其他值表示有错误。
	Code int

	// Message 在 Code 不为 0 时,记录用于描述错误的消息。
	Message string

	// Data 记录返回的数据本体。
	Data T
}

ApiResponse 用于表示返回的数据。

func BadRequestResponse added in v0.4.0

func BadRequestResponse() *ApiResponse[any]

BadRequestResponse 返回一个表示不合规的请求的 ApiResponse 。

func InternalErrorResponse added in v0.4.0

func InternalErrorResponse() *ApiResponse[any]

InternalErrorResponse 返回一个表示不合规的请求的 ApiResponse 。

func SuccessResponse

func SuccessResponse[T any](data T) *ApiResponse[T]

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 ApiResponseBuilderFunc added in v0.6.6

type ApiResponseBuilderFunc func(state *ApiState)

ApiResponseBuilderFunc 用于将函数适配到 ApiResponseBuilder

func (ApiResponseBuilderFunc) BuildResponse added in v0.6.6

func (f ApiResponseBuilderFunc) BuildResponse(state *ApiState)

BuildResponse 实现 [ApiResponseBuilder.BuildResponse] 。

type ApiResponseWriter

type ApiResponseWriter interface {
	// 处理 ApiState.Response ,获得实际需要返回的数据,填入 ApiState.Response* (以 Response 开头)字段。
	// 此方法执行之后, ApiState 中以 Response 开头字段,如 ResponseBody 、 ResponseContentType ,均需要完成赋值。
	// 此方法执行时,若 Response* 字段已经有值,则保留原值,不覆盖。
	WriteResponse(state *ApiState)
}

ApiResponseWriter 处理 ApiResponseBuilder 的处理结果,获得实际需要返回的数据,填入 Response* (以 Response 开头)字段。

type ApiResponseWriterFunc added in v0.6.6

type ApiResponseWriterFunc func(state *ApiState)

ApiResponseWriterFunc 用于将函数适配到 ApiResponseWriter

func (ApiResponseWriterFunc) WriteResponse added in v0.6.6

func (f ApiResponseWriterFunc) WriteResponse(state *ApiState)

WriteResponse 实现 [ApiResponseWriter.WriteResponse] 。

type ApiSetup

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

ApiSetup 用于向 ApiHandler 注册 API 方法。

func (ApiSetup) RegisterMethods

func (setup ApiSetup) RegisterMethods(providerStruct any) ApiSetup

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 any

	// 用于定制输出日志时的日志级别,用于 [ApiLogger] 的日志输出。
	// 若 [ApiLogger.Log] 被调用前没有被赋值(为 0),则 Log 方法被调用后,应将其最终决定使用的级别回填到此字段。
	LogLevel logx.Level

	// LogMessage 用于记录各个处理流程中的日志信息,用于在 [ApiLogger] 中的输出。
	// 最终日志的输出由 [ApiLogger] 决定,这只是一个缓冲( buffer )。
	// key-value 对,与 [logx.Logger.Log] 的 keyValues 参数定义一致。
	LogMessage []any

	// Error 记录 ApiMethodCaller.Call() 方法所调用的具体 WebAPI 方法返回的 error 值;
	// 或记录 ApiDecoder 和 ApiMethodCaller 处理过程中 panic 的错误。没有错误时为 nil 。
	// ApiResponseBuilder.BuildResponse() 能够将此错误转换为对应的 ApiResponse 。
	Error error

	// Response 记录 WebAPI 返回的结果的抽象结构。
	Response *ApiResponse[any]

	// ResponseBody 提供实际返回的 HTTP body 的数据。若为 nil ,则 HTTP 没有 body 。
	// 若实现了 io.ReaderCloser ,则完成 HTTP body 的写入后,会被自动 Close 。
	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

func (s *ApiState) GetCustomData(key any) (any, bool)

GetCustomData 读取 [SetCustomData] 方法存放的值。返回一个 bool 值表示 key 是否存在。

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

func (s *ApiState) SetCustomData(key, value any)

SetCustomData 在当前 *ApiState 中存储一个自定义的值。 原理和 context.WithValue 类似, key 必须是可比较的。

type ApiUserHostResolver

type ApiUserHostResolver interface {
	// FillUserHost 获取发起 HTTP 请求的客户端 IP 地址,并填入 ApiState.UserHost 。
	//
	// HTTP 服务经常通过反向代理访问,可能转好几层,需要通过如 X-Forwarded-For 头获取客户端 IP 。
	// 效果类似于 [http.Request.RemoteAddr] ,但不带端口部分。 IPv6 地址外层的“[]”也会被去掉(如果有)。
	FillUserHost(state *ApiState)
}

ApiUserHostResolver 用于获取发起 HTTP 请求的客户端 IP 地址。 一个请求可能经过多次代理转发,原始地址通常需要从特定 HTTP 头获取,比如 X-Forwarded-For 。

func NewBasicApiUserHostResolver

func NewBasicApiUserHostResolver() ApiUserHostResolver

NewBasicApiUserHostResolver 返回一个预定义的 ApiUserHostResolver 的标准实现。 当实现一个 ApiHandler 时,可基于此实例实现 ApiUserHostResolver 。

type ApiUserHostResolverFunc added in v0.6.6

type ApiUserHostResolverFunc func(state *ApiState)

ApiUserHostResolverFunc 用于将函数适配到 ApiUserHostResolver

func (ApiUserHostResolverFunc) FillUserHost added in v0.6.6

func (f ApiUserHostResolverFunc) FillUserHost(state *ApiState)

FillUserHost 实现 [ApiUserHostResolver.FillUserHost] 。

type ArgumentDecodeFunc added in v0.5.0

type ArgumentDecodeFunc func(state *ApiState, index int, argType reflect.Type) (ok bool, v any, err error)

ArgumentDecodeFunc 用于将函数适配到 [ArgumentDecoder.DecodeArg] 。

func (ArgumentDecodeFunc) DecodeArg added in v0.6.9

func (f ArgumentDecodeFunc) DecodeArg(state *ApiState, index int, argType reflect.Type) (ok bool, v any, err error)

DecodeArg implements [ArgumentDecoder.DecodeArg].

type ArgumentDecoder added in v0.5.0

type ArgumentDecoder interface {
	// DecodeArg 尝试机械 API 方法中的一个参数。
	//
	// 若给定的 API 参数(通过 index 和 argType 识别)可被当前函数解析,则返回 ok=true 及解析结果 v ,或者返回 ok=false 及解析错误;
	// 若当前函数不支持给定参数的解析,则返回无错误的 ok=false 和 v=nil 。
	DecodeArg(state *ApiState, index int, argType reflect.Type) (ok bool, v any, err error)
}

ArgumentDecoder 定义一个过程,此过程用于从 ApiState 中解析得到 API 方法的特定参数的值。 一组实例形成一个解析 API 方法中每个参数的管道 ArgumentDecoderPipeline

type ArgumentDecoderPipeline added in v0.5.0

type ArgumentDecoderPipeline []ArgumentDecoder

ArgumentDecoderPipeline 是 ArgumentDecoder 组成的管道。 实现 ApiDecoder ,此实现要求被调用的每个方法,其参数表中的参数类型是不重复的。

在 [ApiDecoder.Decode] 时,将依次执行管道内的每个 [ArgumentDecoder.DecodeArg] 。 可以通过增减和调整元素的顺序定制执行的过程。

func NewArgumentDecoderPipeline added in v0.5.0

func NewArgumentDecoderPipeline(d ...ArgumentDecoder) ArgumentDecoderPipeline

NewArgumentDecoderPipeline 返回一个 ArgumentDecoderPipeline 。 其第一个元素是预定义的 [ApiStateDecodeFunc] ,用于赋值 *ApiState ; decodeFuncs 会追加在后面。

func (ArgumentDecoderPipeline) Decode added in v0.5.0

func (d ArgumentDecoderPipeline) Decode(state *ApiState)

Decode implements ApiDecoder.Decode.

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 ...any) BadRequestError

CreateBadRequestError 创建一个 BadRequestError 。 message 和 args 指定其消息,使用 fmt.Sprintf() 格式化。 描述信息可能作为 WebAPI 的返回值,被请求者看到,故可能不应当过多暴露程序细节。更具体的错误可以放在 cause 上。

func (BadRequestError) Error

func (e BadRequestError) Error() string

Error 实现 error 接口。

type LogSetup added in v0.5.0

type LogSetup interface {
	// Setup 可将日志信息写入 [ApiState.LogLevel] 和 [ApiState.LogMessage] 。
	Setup(state *ApiState)
}

LogSetup 定义一个过程,此过程用于向 ApiState 填充日志信息。

type LogSetupFunc added in v0.5.0

type LogSetupFunc func(state *ApiState)

LogSetupFunc 用于将函数 [LogSetup.Setup] 。

func (LogSetupFunc) Setup added in v0.6.9

func (f LogSetupFunc) Setup(state *ApiState)

DecodeArg implements [ArgumentDecoder.DecodeArg].

type LogSetupPipeline added in v0.5.0

type LogSetupPipeline []LogSetup

LogSetupPipeline 是 LogSetup 组成的管道,实现 ApiLogger

在 [ApiLogger.Log] 时,依次执行每个 [LogSetup.Setup] ,并将得到的 [ApiState.LogLevel] 和 [ApiState.LogMessage] 输出到日志。 若 [LogLevel] 未被设置,默认使用 logx.LevelInfo 级别。

func NewLogSetupPipeline added in v0.5.0

func NewLogSetupPipeline(s ...LogSetup) LogSetupPipeline

NewLogSetupPipeline 返回一个 LogSetupPipeline

func (LogSetupPipeline) Log added in v0.5.0

func (p LogSetupPipeline) Log(state *ApiState)

Log implements [ApiLogger.Log].

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”; 特别的,单一的“?”会得到一个没有参数名称的参数,值为空字符串。

func (QueryString) Get

func (qs QueryString) Get(name string) (string, bool)

Get 以大小写不敏感方式获取指定名称的参数。返回一个 bool 表示该名称的是参数是否存在。 只能获取有名称的参数(名称可以是空字符串),若需要无名称的,直接访问 Nameless 字段。

type RouteParam added in v0.7.0

type RouteParam struct {
	Key, Value string
}

func AllRouteParams added in v0.7.0

func AllRouteParams(r *http.Request) []RouteParam

AllRouteParams 获取请求中所有的路由参数。若没有路由参数,返回 nil 。

Directories

Path Synopsis
Package logsetup 提供一组预定义的 [webapi.LogSetup] ,以便快速实现 [webapi.ApiLogger] 。
Package logsetup 提供一组预定义的 [webapi.LogSetup] ,以便快速实现 [webapi.ApiLogger] 。
Package slimapi 基于 webapi 包,实现基于 SlimAPI 协议的开发框架。
Package slimapi 基于 webapi 包,实现基于 SlimAPI 协议的开发框架。
slimauth 实现 SlimAuth 协议,它是带有签名校验逻辑的 SlimAPI 的扩展。
slimauth 实现 SlimAuth 协议,它是带有签名校验逻辑的 SlimAPI 的扩展。
webapitest 包提供用于测试 webapi 包的辅助方法。
webapitest 包提供用于测试 webapi 包的辅助方法。

Jump to

Keyboard shortcuts

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