slimapi

package
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: 0

Documentation

Overview

Package slimapi 基于 webapi 包,实现基于 SlimAPI 协议的开发框架。

SlimAPI 是一个基于 HTTP WebAPI 的通信契约。旨在将代码与 HTTP 通信解耦,使编码者可以更多的关注业务逻辑而不是通信方式。

SlimAPI 请求

可以通过 HTTP 的 Content-Type 头指定使用何种格式请求,目前支持的类型如下:

  • GET 不读取 Content-Type 头。
  • POST FORM 表单格式, Content-Type 可以是 application/x-www-form-urlencoded 或 multipart/form-data 。
  • POST JSON 以 JSON 作为数据,值为 application/json 。

也可以不指定 Content-Type 头,而通过`~format`参数指定格式,详见下文。

URL 形式1

http://domain/ApiEntry?~method=METHOD&~format=FORMAT&~callback=CALLBACK

以“~”标记的参数为 API 框架的元参数:

  • ~method:必填;表示被调用的方法的名称。
  • ~format:可选;请求所使用的数据格式,支持get/post/json;此参数在可以在不方面指定`Content-Type`时提供相同的功能。
  • ~callback:可选;JSONP回调函数的名称,一旦制定此参数,返回一个 JSONP 结果,Content-Type: text/javascript 。

参数名称都是大小写不敏感的。`~format`参数优先级高于`Content-Type`,若指定了`~format`,则`Content-Type`的值被忽略。

`~format`的可选值:

  • get 默认值。使用 GET 方式处理。
  • post 效果等同于给定 Content-Type: application/x-www-form-urlencoded
  • json 效果等同于给定 Content-Type: application/json

URL 形式2

http://domain/ApiEntry?METHOD.FORMAT(CALLBACK) 不需要再写参数名字,直接将需要的元参数值追加在URL后面。

同形式1,“.FORMAT”和“(CALLBACK)”是可选的, 省略“.FORMAT”后形如: http://domain/ApiEntry?METHOD(CALLBACK) ; 省略“(CALLBACK)”后形如: http://domain/ApiEntry?METHOD.FORMAT

URL 形式3

通过路由规则,将元参数编排到 URL 路径里。这是最常见的方案: http://domain/ApiEntry/METHOD 这里 METHOD 就是元参数 ~method 。

SlimAPI 请求参数的格式

请求参数

  • GET 参数体现在 URL 上,形如 data=1&name=abc&time=2014-4-8 。
  • 表单 以 POST 方式放在 HTTP BODY 中。
  • JSON 只能使用 POST 方式上送。

可在 GET/表单参数中传递简单的数组,数组元素间使用 ~ 分割,如 1~2~3~4~5 可表示数组 [1, 2, 3, 4, 5]。

在GET/表单格式下:

data=1&name=abc&time=2014-4-8&array=1~2~3~4

与JSON格式下的下面内容等价:

{ "data":1, "name": "abc", "time": "2014-4-8", "array": [1, 2, 3, 4] }

日期格式使用字符串的 yyyy-MM-dd HH:mm:ss 格式,默认为 UTC 时间。也支持 RFC3339 ,这种格式自带时区。

使用 multipart/form-data 传递复杂参数

在 multipart/form-data 的 body 上,通常每个 part 表示一个 text/plain 类型的简单值。 SlimAPI 支持以 JSON 形式传递复杂的参数:

  • part 的 Content-Type 必须是 application/json 。
  • part 的 Content-Disposition 必须带有 filename ,具有任意非空值。

下面的请求等同于用 JSON 传递了 {"A":"123", "B":{"B1":"v1", "B2":"v2"}} :

POST your_url
Content-Type: multipart/form-data; boundary=----xyz

----xyz
Content-Disposition: form-data; name="A"

123
----xyz
Content-Disposition: form-data; name="B"; filename="blob"
Content-Type: application/json

{"B1":"v1","B2":"v2"}
----xyz--

SlimAPI 回执格式

若指定了 ~callback 参数,则返回结果为 JSONP 格式: Content-Type: text/javascript ;否则为 JSON 格式: Content-Type: application/json 。

状态码总是200,具体异常码需要从Code字段判定。数据装在一个基本的信封中,信封格式如下:

{ Code: 0, Message: "", Data: {} }

- Code 0为API调用成功未见异常,非0值为异常:
	- 1-999 API请求、通信及运行时异常,尽可能与 HTTP 状态码一致:
		- 500 服务端内部异常。
		- 400 请求参数或报文错误。
		- 403 客户端无访问权限。
	- 其他约定:
	- -1 未明确定义的错误。
	- 1000-9999 预留
	- 大于等于10000为业务预定义异常,由具体API自行定义,但建议至少分为用户可见和不可见两个区间:
		- 10000-19999 建议保留为不提示给用户的业务异常,对接 API 的客户端对于这些异常码,对用户提示一个统一的如“网络异常”的错误。
		- 20000-29999 对接 API 的客户端可直接将 Message 展示给用户,用于展示的错误消息需要由服务端控制的场景。
- Message 附加信息, Code 不为0时记录错误描述,可为空字符串。
- Data 返回的主数据,不同API各不相同,其所有可能形式如下:
	- 若API没有返回值,则为 null 。
	- 对于返回布尔型结果的 API ,Data 为 true 或 false 。
	- 对于返回数值结果的 API ,Data即为数值,如:123.654 。
	- 对于返回字符串结果的 API , Data 为字符串,如:"string value" 。
	- 日期也作为字符串,参照前面提到的日期格式。
	- 对于返回集合的 API , Data 为数组,如: ["result1", "result2"] 。
	- 对于返回复杂对象的 API ,Data 为 JSON object ,如:{ "Field1": "Value1", "Field2": "Value2" } 。

Index

Constants

View Source
const (
	// SlimAPI 协议里默认的时间格式: yyyy-MM-dd HH:mm:ss 。 API 输出 JSON 时使用此格式。
	TimeFormat = "2006-01-02 15:04:05"
)

Variables

View Source
var Conv = func() conv.Conv {
	_convConf.CustomConverters = func() []conv.ConvertFunc {
		var (
			typFilePart   = reflect.TypeOf(&FilePart{})
			typFileHeader = reflect.TypeOf(&multipart.FileHeader{})
			typByteSlice  = reflect.TypeOf([]byte{})
		)

		filePartToFilePart := func(value interface{}, typ reflect.Type) (result interface{}, err error) {
			if typ != typFilePart {
				return
			}

			f, ok := value.(*FilePart)
			if !ok {
				err = fmt.Errorf("require *slimapi.FilePart, got %T", value)
				return
			}

			return f, nil
		}

		filePartToFileHeader := func(value interface{}, typ reflect.Type) (result interface{}, err error) {
			if typ != typFileHeader {
				return
			}

			f, ok := value.(*FilePart)
			if !ok {
				err = fmt.Errorf("require *slimapi.FilePart, got %T", value)
				return
			}

			return f.FileHeader, nil
		}

		filePartToBytes := func(value interface{}, typ reflect.Type) (result interface{}, err error) {
			if typ != typByteSlice {
				return
			}

			f, ok := value.(*FilePart)
			if !ok {
				return
			}

			return f.ReadAll()
		}

		jsonFilePartToAny := func(value interface{}, typ reflect.Type) (result interface{}, err error) {
			f, ok := value.(*FilePart)
			if !ok || !f.IsJson() {
				return
			}

			jsonValue := f.JsonValue()
			result, err = _internalConv.ConvertType(jsonValue, typ)
			return
		}

		return []conv.ConvertFunc{
			filePartToFilePart,
			filePartToFileHeader,
			filePartToBytes,
			jsonFilePartToAny,
		}
	}()

	return conv.Conv{Conf: _convConf}
}()

Conv 是用于 SlimAPI 的 conv.Conv 实例,它支持:

  • 使用大小写不敏感(case-insensitive)的方式处理字段。
  • 支持 SlimAPI 规定的时间格式 yyyyMMdd HH:mm:ss 。
  • 支持字符串到数组的转换,使用 ~ 分割,如将 "1~2~3" 转为 [1, 2, 3] 。

特别的,用于支持 multipart/form-data 的文件上传,如果输入 *FilePart

  • 目标值类型是 *multipart.FileHeader 时,原样返回输入值,不做转换。
  • 目标值时 []byte 时,将其数据读取出来。
  • 目标值时其他类型时,若此分部的 Content-Type 为 application/json ,则将其内容作为 JSON 读取,并将此 JSON 反序列化到目标值。
View Source
var LogBody = logBody{}

LogBody 实现 webapi.LogSetup ,用于记录请求的 body 的相关信息。

这是一个单例。

View Source
var StructArgumentDecoder = slimApiMethodStructArgDecoder{}

StructArgumentDecoder 是一个 webapi.ArgumentDecoder , 定义了 SlimAPI 协议的参数解析过程,用于方法参数表中 struct 类型的参数。

这是一个单例。

Functions

func NewSlimApiDecoder

func NewSlimApiDecoder() webapi.ArgumentDecoderPipeline

NewSlimApiDecoder 返回用于 SlimAPI 协议的 webapi.ApiDecoder 实现。

func NewSlimApiHandler

func NewSlimApiHandler(name string) *webapi.ApiHandlerWrapper

NewSlimApiHandler 创建一个实现 SlimAPI 协议的 webapi.ApiHandlerWrapper 。 可通过替换其成员实现接口的定制。

func NewSlimApiLogger added in v0.6.0

func NewSlimApiLogger() webapi.LogSetupPipeline

NewSlimApiLogger 返回用于 SlimAPI 协议的 webapi.ApiLogger 实现。

func NewSlimApiNameResolver added in v0.3.3

func NewSlimApiNameResolver() webapi.ApiNameResolver

NewSlimApiNameResolver 返回用于 SlimAPI 协议的 webapi.ApiNameResolver 实现。

func NewSlimApiResponseWriter added in v0.6.0

func NewSlimApiResponseWriter() webapi.ApiResponseWriter

NewSlimApiResponseWriter 返回用于 SlimAPI 协议的 webapi.ApiResponseWriter 实现。 该实现是无状态且线程安全的。

func ParseTime added in v0.6.4

func ParseTime(v string) (time.Time, error)

ParseTime 解析 SlimAPI 的时间格式,默认 yyyyMMdd HH:mm:ss 时区为 UTC ,如果解析失败再用默认的格式( RFC3339 )处理。

func SupportedHttpMethods added in v0.6.0

func SupportedHttpMethods() []string

SupportedHttpMethods 返回 SlimAPI 支持的 HTTP 请求方法。 当前支持 GET 和 POST 。

Types

type FilePart added in v0.8.0

type FilePart struct {
	*multipart.FileHeader // 原始的 FileHeader 。
	// contains filtered or unexported fields
}

FilePart 用于封装一个 *multipart.FileHeader ,用于 Conv 对象进行类型转换, 以支持 multipart/form-data 方式的参数及文件上传。

func NewFilePart added in v0.8.0

func NewFilePart(fh *multipart.FileHeader) (*FilePart, error)

NewFilePart 创建一个 FilePart 。

如果 part 带有 HTTP 头 Content-Type:application/json ,则 JSON 内容会被读取并校验其格式。 若读取或校验失败,返回对应的错误。

func (*FilePart) ContentType added in v0.8.0

func (x *FilePart) ContentType() string

ContentType 返货当前 part 的 Content-Type 。 若没有此头部,返回空字符串;若此头部重复多次,仅返回第一个值。

func (*FilePart) IsJson added in v0.8.0

func (x *FilePart) IsJson() bool

IsJson 判断当前 part 是否具有 HTTP 头 Content-Type:application/json 。

func (*FilePart) JsonValue added in v0.8.0

func (x *FilePart) JsonValue() any

JsonValue 返回当前 part 的 JSON 数据的 json.Unmarshal 反序列化结果。 若当前 part 不具有 Content-Type:application/json ,则 panic 。

func (*FilePart) MarshalJSON added in v0.8.0

func (x *FilePart) MarshalJSON() ([]byte, error)

MarshalJSON 实现 json.Marshaler 。它以 JSON 形式返回对于当前 FilePart 的描述信息。

func (*FilePart) ReadAll added in v0.8.0

func (x *FilePart) ReadAll() (res []byte, err error)

ReadAll 读取当前 part 的全部数据。 此方法可被重复调用。

type SlimApiInvoker added in v0.6.0

type SlimApiInvoker[TParam, TData any] struct {
	// 目标 URL 。
	Uri string

	// 若不为 nil ,则在 [http.Client.Do] 之前,调用此函数对当前请求进行处理。
	RequestSetup func(r *http.Request) error
}

SlimApiInvoker 用于调用一个 SlimAPI 。

TParam 是输入参数的类型; TData 对应输出的 webapi.ApiResponse.Data

func NewSlimApiInvoker added in v0.6.0

func NewSlimApiInvoker[TParam, TData any](uri string) *SlimApiInvoker[TParam, TData]

SlimApiInvoker 创建一个 SlimApiInvoker 实例。

func (SlimApiInvoker[TParam, TData]) Do added in v0.6.0

func (x SlimApiInvoker[TParam, TData]) Do(params TParam) (data TData, err error)

Do 执行请求并在 webapi.ApiResponse.Code 为 0 时返回 webapi.ApiResponse.Data 。 若 Code 不是 0 ,则返回 errx.BizError

func (SlimApiInvoker[TParam, TData]) DoRaw added in v0.6.0

func (x SlimApiInvoker[TParam, TData]) DoRaw(params TParam) (res webapi.ApiResponse[TData], err error)

DoRaw 执行请求,并返回原始的 webapi.ApiResponse ,不会判断对应的 Code 值。

请求总是以 Content-Type: application/json 方式发送, params 是请求的参数,需能够被 JSON 序列化。

func (SlimApiInvoker[TParam, TData]) MustDo added in v0.6.0

func (x SlimApiInvoker[TParam, TData]) MustDo(params TParam) TData

MustDo 是 [Do] 的 panic 版本。

func (SlimApiInvoker[TParam, TData]) MustDoRaw added in v0.6.0

func (x SlimApiInvoker[TParam, TData]) MustDoRaw(params TParam) webapi.ApiResponse[TData]

MustDoRaw 是 [DoRaw] 的 panic 版本。

type Time added in v0.3.0

type Time time.Time

Time 描述 SlimAPI 协议中的时间。

在 API response 中,使用此类型,可输出 SlimAPI 格式的时间。 e.g.

type SomeResponse struct {
    CreateTime time.Time    // 在 JSON 中使用默认的格式(RFC3339)输出。
    UpdateTime slimapi.Time // 在 JSON 中使用 SlimAPI 规定的格式输出: yyyy-MM-dd HH:mm:ss 。
}

func (Time) MarshalJSON added in v0.3.0

func (t Time) MarshalJSON() ([]byte, error)

Implements json.Marshaler.

func (Time) String added in v0.3.0

func (t Time) String() string

Implements fmt.Stringer.

func (Time) Time added in v0.3.0

func (t Time) Time() time.Time

Time 将 slimapi.Time 转换到标准库的 time.Time 。

Jump to

Keyboard shortcuts

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