Releases: danielgtaylor/huma
v1.14.3
What's Changed
- fix: reset recovery middleware buffer by @danielgtaylor in #572
Full Changelog: v1.14.2...v1.14.3
v2.22.1
Overview
This patch release fixes a bug where the order of operations when resetting a buffer could cause a race condition when putting that buffer back into the shared sync.Pool
for re-use when reading in request bodies.
What's Changed
- fix: order of operations when resetting buffer by @danielgtaylor in #553
Full Changelog: v2.22.0...v2.22.1
v2.22.0
Sponsors
A big thank you to our new sponsor:
Overview
Minimum Go Version: 1.21
The minimum Go version has been upgraded to 1.21, in alignment with the official Go policy. This enables us to fix some critical vulnerabilities with optional dependencies via dependabot and allows the code to be updated to use newer packages like slices
, modernizing the codebase.
Each major Go release is supported until there are two newer major releases. For example, Go 1.5 was supported until the Go 1.7 release, and Go 1.6 was supported until the Go 1.8 release.
https://go.dev/doc/devel/release
Fixes Raw Body Race Condition
This release fixes a critical bug where you could run into a race condition using a shared buffer when accessing a request's RawBody []byte
field. The buffer was getting returned to the sync.Pool
too early, resulting in multiple requests having concurrent access. For handlers which register needing access to the RawBody
field, returning the buffer to the pool is now deferred until after then entire handler has run, fixing the issue.
Warning
If you use the RawBody
feature, you should upgrade immediately. This bug results in incorrect/corrupted data.
Better encoding.TextUnmarshaler
Support
Support for types which implement encoding.TextUnmarshaler
has been improved. The types are now treated as a JSON Schema string
by default, making it easier to set up validation and defaults without needing to provide a custom schema via huma.SchemaProvider
. Among other things this can be used for custom date/time types:
type MyDate time.Time
func (d *MyDate) UnmarshalText(data []byte) error {
t, err := time.Parse(time.RFC3339, string(data))
if err != nil {
return err
}
*d = MyDate(t)
return nil
}
// Later use it in a request
type Request struct {
Date MyDate `json:"date" format:"date-time" example:"2024-01-01T12:00:00Z"`
}
Precompute Schema Validation
Schema validation messages are no longer required to be precomputed manually with a call to schema.PrecomputeMessages()
as this now happens at operation registration time. This simplifies using custom schemas and makes it possible to define them inline with the operation.
If you modify a schema after registration, you must still call PrecomputeMessages()
manually to update the messages.
Fix Nil Response Panic
If an operation is registered as returning a body and a handler mistakenly invokes return nil, nil
(meaning no response, no error) this caused a panic as the body is required. This release changes that behavior to no longer panic, but instead return the operation's default status code instead.
What's Changed
- fix: race by deferring the return of buf to sync.Pool when using RawBody by @nunoo in #542
- fix: automatically precompute schema validation messages by @danielgtaylor in #545
- fix: if err & response are nil, return default status by @danielgtaylor in #546
- feat: Update minimum Go version to 1.21 by @danielgtaylor in #547
- chore(deps): bump github.com/gofiber/fiber/v2 from 2.52.1 to 2.52.5 by @dependabot in #549
- feat: treat encoding.TextUnmarshaler as string in schema by @danielgtaylor in #550
New Contributors
Full Changelog: v2.21.0...v2.22.0
v2.21.0
Overview
Better Support for Default/Example in Custom Schemas
Fixes an issue where custom schemas could have values overwritten by the default instead of using the given value. For example:
type GreetingType int
func (*GreetingType) Schema(r huma.Registry) *huma.Schema {
schema := &huma.Schema{
Type: huma.TypeInteger,
Default: 10,
Examples: []any{1},
}
return schema
}
Better Errors When Using Discriminators
OpenAPI supports using a discriminator field in schemas that use oneOf
to determine which of the included schemas to validate against. Huma now uses this information to generate better error messages like expected required property color to be present
instead of just saying it expected one of the schemas to match. Also handles problems with the discriminator type and value mapping. Example https://go.dev/play/p/5gkNczNJ_jK:
type Cat struct {
Name string `json:"name" minLength:"2" maxLength:"10"`
Kind string `json:"kind" enum:"cat"`
}
type Dog struct {
Color string `json:"color" enum:"black,white,brown"`
Kind string `json:"kind" enum:"dog"`
}
type DogOrCat struct {
Kind string `json:"kind" enum:"cat,dog"`
}
func (v DogOrCat) Schema(r huma.Registry) *huma.Schema {
catSchema := r.Schema(reflect.TypeOf(Cat{}), true, "Cat")
dogSchema := r.Schema(reflect.TypeOf(Dog{}), true, "Dog")
return &huma.Schema{
Type: huma.TypeObject,
Description: "Animal",
OneOf: []*huma.Schema{
{Ref: catSchema.Ref},
{Ref: dogSchema.Ref},
},
Discriminator: &huma.Discriminator{
PropertyName: "kind",
Mapping: map[string]string{
"cat": catSchema.Ref,
"dog": dogSchema.Ref,
},
},
}
}
// ...
huma.Put(api, "/demo", func(ctx context.Context, input *struct {
Body DogOrCat
}) (*DemoResponse, error) {
resp := &DemoResponse{}
resp.Body.Message = "You sent a " + input.Body.Kind
return resp, nil
})
What's Changed
- fix(schema): default value not work by @fourcels in #531
- fix(typo): accmplished -> accomplished by @superstas in #534
- fix(schema): schema example not work in Parameter by @fourcels in #532
- #533: Add Validation for Discriminator with OneOf and Mapping. by @superstas in #536
Full Changelog: v2.20.0...v2.21.0
v2.20.0
Overview
Sponsors
Thank you to Zuplo for sponsoring the project.
Fixed Validation Tags & Referenced Schemas
Sometimes schemas and schemas in references wound up getting overwritten with default values for validation like minimum
, maximum
, minLength
, maxLength
, as well as skipping calling TransformSchema
. This is now fixed to behave as expected by derefencing structs and only setting validation values when the tag is actually present.
Customizable Validation Errors
Validation errors are now completely customizable as globals in the library.
// Set a custom message for minimum validation failure.
huma.MsgExpectedMinimumNumber = "expected number bigger than or equal to %v"
You can also change the function used to format error messages via huma.ErrorFormatter
. This must be overwritten before generating any schemas, as the generated messages are cached at schema creation time.
var ErrorFormatter func(format string, a ...any) string = fmt.Sprintf
Nullable Slices
Due to the way nil
slices get encoded in Go as null
in JSON and other formats, we now generate array schemas as nullable by default. See also the discussion and links to JSON v2 at golang/go#37711.
What's Changed
- fix(schema): proper minLength, maxLength in generated schemas. by @superstas in #513
- fix(schema): proper minimum, maximum in generated schemas. by @superstas in #515
- fix(schema): add dereferencing for SchemaFromType by @superstas in #518
- feat: add zuplo sponsorship by @danielgtaylor in #501
- docs: fix formatting in sponsors by @danielgtaylor in #523
- feat: make validation error messages customizable by @smacker in #520
- fix: nullable schemas for arrays/slices by @lsdch in #527
New Contributors
- @superstas made their first contribution in #513
- @smacker made their first contribution in #520
Full Changelog: v2.19.0...v2.20.0
v2.19.0
Overview
Sponsors
A big thank you to our new sponsor:
Multipart Form File Metadata
It's now possible to get filename & size metadata information from multipart form files.
huma.Post(api, "/form-example", func(ctx context.Context, input *struct{
RawBody huma.MultipartFormFiles[struct {
HelloWorld huma.FormFile `form:"file" contentType:"text/plain" required:"true"`
}]
}) (*struct{}, error) {
fileData := input.RawBody.Data()
fmt.Println( fileData.HelloWorld.Filename)
fmt.Println( fileData.HelloWorld.Size)
}
Easier Custom Context When Testing
It's now easier to pass a custom context to operations in the test API. Instead of having to create a custom request with its own context and manually call the adapter you can now use the methods like GetCtx
instead of Get
.
_, api := humatest.New(t)
ctx := context.Background() // define your necessary context
resp := api.GetCtx(ctx, "/greeting/world") // provide it using the 'Ctx' suffixed methods
Exploded Query Params
It's now possible to use the OpenAPI explode
feature where query params are passed multiple times rather than using comma separated values.
huma.Get(api, "/example", func(ctx context.Context, input *struct{
Value []string `query:"value,explode"`
}) (*struct{}, error) {
fmt.Println(input.Value)
return nil, nil
})
You can then make requests like GET /example?value=foo&value=bar
.
Autopatch Schema Improvements
Autopatch now uses the PUT
schema (modified to all be optional) rather than just relying on an object
with any allowed properties, which improves documentation for users. This is automatic so there is no need to configure anything new.
Other Improvements
- Performance improvement by removing the response body from panics which could be very large.
- Fixes to min/max items schema generation when using arrays.
- Remove
slices
dependency to continue to support Go 1.20 until 1.23 is released (we will support the latest two major versions just like the Go project itself)
What's Changed
- fix: expose metadata of decoded multipart form files by @lsdch in #466
- Extend TestAPI interface to allow for custom context.Context by @coury-clark in #469
- Update README_CN.md by @Ivlyth in #477
- remove response body from panic message by @austincollinpena in #479
- fix(schema): proper array minItems, maxItems and doc reporting in generated schemas by @Grumpfy in #485
- fix: remove slices dependency to better support Go 1.20 by @danielgtaylor in #497
- Implement exploded query parameters by @csmarchbanks in #498
- Improvement Autopatch (adding a body) by @ScriptType in #496
- docs: add new sponsor by @danielgtaylor in #506
New Contributors
- @coury-clark made their first contribution in #469
- @Ivlyth made their first contribution in #477
- @Grumpfy made their first contribution in #485
- @csmarchbanks made their first contribution in #498
- @ScriptType made their first contribution in #496
Full Changelog: v2.18.0...v2.19.0
v2.18.0
Overview
Better Multipart Files Uploads
You can now use huma.MultipartFormFiles[YourType]
as the request's RawBody
in order to handle multipart file uploads. Files can be limited to specific content types and required or optional. Example:
type FileData struct {
// This is an example, any number of `multipart.File` fields can be defined.
// Nested structs are not supported.
SomeFile multipart.File `form-data:"some_file" content-type:"image/png" required:"true"`
SeveralFiles []multipart.File `form-data:"several_files" content-type:"image/png,image/jpeg" required:"true"`
}
type FileHandlerInput struct {
RawBody huma.MultipartFormFiles[FileData]
}
func FileHandler(ctx context.Context, input *FileHandlerInput) (*struct{}, error) {
fileData := input.RawBody.Data()
DoSomeThingWith(fileData.SomeFile)
OrSomethingElseWith(fileData.SeveralFiles)
}
huma.Register(api,
huma.Operation{
Path: "/handle-files",
Method: http.MethodPost,
OperationID: "Handle files",
}, FileHandler)
Schema Transformers
It's now possible to have types implement a schema transformer, which lets them modify the generated schema for the type. This option lives in between using the generated types and providing your own schema, and makes it a bit easier to modify the generated schema by not needing you to call into the registry manually. This is the interface:
type SchemaTransformer interface {
TransformSchema(r Registry, s *Schema) *Schema
}
Simple example:
type MyInput struct {
Field string `json:"field"`
}
func (i *MyInput) TransformSchema(r huma.Registry, s *huma.Schema) *huma.Schema {
s.Description = "I am an override"
return s
}
What's Changed
- Fix typo in SSE doc by @op-tmplt in #448
- Feature: handling files from
multipart/form-data
request by @lsdch in #415 - feat: allow modifying generated schema by implementing SchemaTransformer interface by @lsdch in #456
- fix: type schema description not work by @fourcels in #462
New Contributors
Full Changelog: v2.17.0...v2.18.0
v2.17.0
Overview
Convenience Method Operation Modifiers
You can now add modifier functions when registering operations using convenience methods like huma.Get
:
func OperationTags(tags ...string) func(o *Operation) {
return func(o *Operation) {
o.Tags = tags
}
}
huma.Get(api, "/demo", myHandler, OperationTags("one", "two"))
Use this to build out whatever functionality you need to simplify registration. These can also be composed & joined easily to give a concise way to register operations without falling back to huma.Register
directly.
Request Remote Address Access
It's now possible to access the requests's RemoteAddr
field through huma.Context
for use in middleware and/or resolvers, which works with all routers:
func MyMiddleware(ctx huma.Context, next func(huma.Context)) {
fmt.Println("Request address", ctx.RemoteAddr())
next(ctx)
}
Fix Unmarshaling of Embedded Body
Unmarshaling of embedded structs with a body field now works as expected:
type BodyContainer struct {
Body struct {
Name string `json:"name"`
}
}
huma.Register(api, huma.Operation{
Method: http.MethodPost,
Path: "/body",
}, func(ctx context.Context, input *struct {
BodyContainer
}) (*struct{}, error) {
// Do something with `input.Body.Name`...
return nil, nil
})
What's Changed
- feat: convenience methods with operationHandlers by @fourcels in #434
- fix: race condition in CLI tests by @danielgtaylor in #436
- docs: add new sponsor and quote by @danielgtaylor in #437
- fix: unmarshaling of request body when using struct embedding by @lsdch in #440
- feat: add request remote address to context by @danielgtaylor in #447
New Contributors
Full Changelog: v2.16.0...v2.17.0
v2.16.0
Overview
Drop Deprecated Chi v4 Adapter
This release drops Chi v4 support. Chi v4 has been deprecated & replaced with Chi v5 since 2021, and was included to help migrate from Huma v1 to v2. Huma v2 has now been out for about six months. Keeping Chi v4 in the main package results in extra dependencies and deprecation warnings from automated tools like dependabot. It is highly recommended to discontinue using Chi v4.
If you wish to continue using Chi v4, please copy the v4 adapter from https://github.com/danielgtaylor/huma/blob/v2.15.0/adapters/humachi/humachi.go into your own project. With that simple change you can migrate off at your own pace while continuing to get new Huma releases.
Better Panics
Some panic messages have been improved to be more helpful for users, for example letting them know that the response type must be a struct rather than some confusing reflection panic.
What's Changed
- feat!: drop chi v4 adapter by @costela in #427
- panic with more descriptive messages by @ssoroka in #431
Full Changelog: v2.15.0...v2.16.0
v2.15.0
Sponsors
A big thank you to our new sponsor:
Overview
Schema Discriminator Support
Basic support for the OpenAPI 3.1 discriminator which gives hints to clients that the value of a field defines the type of the response. This is not currently exposed via tags but can be used when manually creating schemas:
s := &huma.Schema{
OneOf: []*huma.Schema{
{Type: "object", Properties: map[string]*huma.Schema{
"type": {Type: "string", Enum: []any{"foo"}},
"foo": {Type: "string"},
}},
{Type: "object", Properties: map[string]*huma.Schema{
"type": {Type: "string", Enum: []any{"bar"}},
"bar": {Type: "string"},
}},
},
Discriminator: &huma.Discriminator{
PropertyName: "type",
Mapping: map[string]string{
"foo": "#/components/schemas/Foo",
"bar": "#/components/schemas/Bar",
},
},
}
Anonymous Struct Name Hints
Allow providing name hints via field tags for anonymous structs defined inline. This gives a bit more control over the JSON Schema type names:
type EndpointInput struct {
Body struct {
SomeData string `json:"some_data"`
} `name-hint:"SomeName"`
}
Better File Upload UI Support
A contentMediaType
field is generated for fields which are format: "binary"
which enables a better UI for uploading files in the generated docs.
Bug Fixes
The generated $schema
field now uses http
instead of https
when the host is 127.0.0.1
. Previously this was only the case for localhost
.
Pointer types with custom schemas are now better supported by dereferencing the pointer to the underlying type before checking for the custom schema interface implementation.
The built-in Flow router has a fix applied to handle path params that are percent encoded with slashes. Fix has also been submitted upstream.
Fixed a possible panic in the schema link transformer when passed nil
body types.
Updated the precondition error locations to match the rest of the project. request.headers.If-Match
→ headers.If-Match
as we no longer explicitly state it's in the request. It's always in the request.
Fixed an example in the docs that was resulting in an error due to a typo.
What's Changed
- Use plain http in $schema for 127.0.0.1 by @davidolrik in #408
- fix: check if struct implements interface SchemaProvider after deref by @lennycampino in #413
- fix: Add support for Percent-Encoding RFC 3986 by @chilic in #411
- fix: more robust nil check for link transformer by @danielgtaylor in #418
- feat: basic schema discriminator support by @danielgtaylor in #419
- fix: precondition error location to match other errors by @danielgtaylor in #420
- Allow providing name hints using tags for anonymous body structs by @lsdch in #416
- fix: cli name example in docs by @danielgtaylor in #421
- Add contentMediaType field to generated schema when format is binary by @lsdch in #422
New Contributors
- @davidolrik made their first contribution in #408
- @lennycampino made their first contribution in #413
- @chilic made their first contribution in #411
Full Changelog: v2.14.0...v2.15.0