Skip to content

模式自定义#

操作模式#

输入/输出体的生成模式可以通过几种方式自定义。首先,在注册操作时,您可以提供自己的请求和/或响应模式,如果您想覆盖整个体。自动生成仅在 OpenAPI 中未提供自己的模式时适用。

code.go
// 使用自定义输入体模式注册操作。
huma.Register(api, huma.Operation{
	OperationID: "my-operation",
	Method:      http.MethodPut,
	Path:        "/things/{thing-id}",
	Summary:     "Update a thing",
	RequestBody: &huma.RequestBody{
		Description: "我的自定义请求模式",
		Content: map[string]*huma.MediaType{
			"application/json": {
				Schema: &huma.Schema{
					Type: 		 huma.TypeObject,
					Properties: map[string]*huma.Schema{
						"foo": {
							Type: huma.TypeString,
							Extensions: map[string]any{
								"x-custom-thing": "abc123",
							},
						},
					},
				},
			},
		},
	},
}, func(ctx context.Context, input *MyInput) (*MyOutput, error) {
	// 实现代码在此处...
	return nil, nil
})

字段模式#

其次,可以按字段基础进行自定义,通过实现一个特殊接口来获取模式,从而允许您例如将额外功能封装在该字段中。这是该接口:

code.go
// SchemaProvider 是一个接口,可以由类型实现,以为其自身提供自定义模式,
// 覆盖内置模式生成。这可用于具有自身特殊序列化规则的自定义类型。
type SchemaProvider interface {
	Schema(r huma.Registry) *huma.Schema
}

huma.Registry 会传递给您,并可用于获取嵌入式结构的模式或引用。以下是一个示例,其中我们想要知道字段在作为请求体的一部分发送时是被省略、null 还是值。首先,我们从定义自定义泛型结构开始:

code.go
// OmittableNullable 是一个字段,可以从输入中省略、
// 设置为 `null` 或设置为值。每种状态都会被跟踪,并在处理代码中可检查。
type OmittableNullable[T any] struct {
	Sent  bool
	Null  bool
	Value T
}

// UnmarshalJSON 从 JSON 输入反序列化此值。
func (o *OmittableNullable[T]) UnmarshalJSON(b []byte) error {
	if len(b) > 0 {
		o.Sent = true
		if bytes.Equal(b, []byte("null")) {
			o.Null = true
			return nil
		}
		return json.Unmarshal(b, &o.Value)
	}
	return nil
}

// Schema 返回表示此值在传输中的模式。
// 它返回包含类型的模式。
func (o OmittableNullable[T]) Schema(r huma.Registry) *huma.Schema {
	return r.Schema(reflect.TypeOf(o.Value), true, "")
}

以下是它在操作中的使用方式:

type MyResponse struct {
	Body struct {
		Message string `json:"message"`
	}
}

huma.Register(api, huma.Operation{
	OperationID: "omittable",
	Method:      http.MethodPost,
	Path:        "/omittable",
	Summary:     "Omittable / nullable example",
}, func(ctx context.Context, input *struct {
	// 将体设置为指针使其可选,因为它可能为 `nil`。
	Body *struct {
		Name OmittableNullable[string] `json:"name,omitempty" maxLength:"10"`
	}
}) (*MyResponse, error) {
	resp := &MyResponse{}
	if input.Body == nil {
		resp.Body.Message = "Body was not sent"
	} else if !input.Body.Name.Sent {
		resp.Body.Message = "Name was omitted from the request"
	} else if input.Body.Name.Null {
		resp.Body.Message = "Name was set to null"
	} else {
		resp.Body.Message = "Name was set to: " + input.Body.Name.Value
	}
	return resp, nil
})

如果您查看生成的文档,您会看到 name 字段的类型是 string,它是可选的,最大长度为 10,这表明自定义模式正确地用于替换为 OmittableNullable[string] 结构生成的一个。

查看 https://github.com/danielgtaylor/huma/blob/main/examples/omit/main.go 以获取完整示例以及如何调用它。这只是使用字段自定义模式可能性的冰山一角。

深入了解#