Skip to content

v2.24.0

Compare
Choose a tag to compare
@danielgtaylor danielgtaylor released this 18 Oct 16:45
· 70 commits to main since this release
c6191e3

Overview

Better Support of String Subtype Slice Params

It's now possible to use types based on string like you commonly see for enumerations as slice inputs to Huma operations.

type MyEnum string

const (
	Value1 MyEnum = "value1"
	Value2 MyEnum = "value2"
	// ...
)

huma.Get(api, "/example", func(ctx context.Context, input *struct{
	Example []MyEnum `query:"example" enum:"value1,value2"`
}) (*struct{}, error) {
	// ...
}

Better Support of non-Object Refs

Fixes a bug that prevented deliberate refs of nullable non-objects from being used due to a panic. It's now possible to do something like this to automatically add enum values from a type when generating the schema and use a $ref in the JSON Schema:

type InstitutionKind string

const (
	Lab                InstitutionKind = "Lab"
	FoundingAgency     InstitutionKind = "FundingAgency"
	SequencingPlatform InstitutionKind = "SequencingPlatform"
	Other              InstitutionKind = "Other"
)

var InstitutionKindValues = []InstitutionKind{
	Lab,
	FoundingAgency,
	SequencingPlatform,
	Other,
}

// Register enum in OpenAPI specification
func (u InstitutionKind) Schema(r huma.Registry) *huma.Schema {
  if r.Map()["InstitutionKind"] == nil {
    schemaRef := r.Schema(reflect.TypeOf(""), false, "InstitutionKind")
    schemaRef.Title = "InstitutionKind"
    for _, v := range InstitutionKindValues {
      schemaRef.Enum = append(schemaRef.Enum, string(v))
    }
    r.Map()["InstitutionKind"] = schemaRef
  }

	return &huma.Schema{Ref: "#/components/schemas/InstitutionKind"}
}

Fix Empty Security Marshaling

The empty security object has semantic meaning in OpenAPI 3.x which enables you to override a global security setting to make one or more operations public. It's now possible to do so:

huma.Register(api, huma.Operation{
	OperationID: "GetUser",
	Method:      http.MethodGet,
	Path:        "/user/{id}",
	Security:    []map[string][]string{}, // This will not require security!
}, func(ctx context.Context, input *GetUserInput) (*GetUserOutput, error) {
	resp := &GetUserOutput{}
	resp.Body.Message = "GetUser with ID: " + input.ID + " works!"
	return resp, nil
})

Expanded Adapter Interface

The huma.Adapter interface now has methods for getting the HTTP version and TLS info of the incoming request, which enables better tracing middleware using e.g. OpenTelemetry.

Schema Transformers Automatically Call schema.PrecomputeMessages()

Schema transformers may modify the schema in ways that precomputed messages & validation cache data are no longer valid. This change makes sure to recompute them if the schema has been modified, preventing potential panics.

Configurable Array Nullability

Huma v2.20.0 introduced nullable JSON Schema arrays for Go slices due to the default behavior of Go's JSON marshaler. This change resulted in some clients (e.g. Typescript) now needing to do extra checks even when the service is sure it will never return a nil slice. This release includes a way to change the global default Huma behavior by setting huma.DefaultArrayNullable = false. It is still possible to set nullable on each field to override this behavior, but now it is easier to do so globally for those who wish to use the old (arguably less correct) behavior.

Better SSE Support

This release includes some http.ResponseController behavior to unwrap response writers to try and get access to SetWriteDeadline and Flush methods on response writers. This prevents error messages from being dumped into the console and enables Gin SSE support for the first time with the Huma sse package. Most routers should Just Work ™️ with SSE now.

Read-Only & Write-Only Behavior Clarification

The read and write-only behavior of Huma validation has been clarified in the docs. See https://huma.rocks/features/request-validation/#read-and-write-only to ensure it works as you expect.

What's Changed

New Contributors

Full Changelog: v2.23.0...v2.24.0