github danielgtaylor/huma v2.40.0

5 hours ago

Overview

This release adds native support for stdlib UUIDs, cuts compile times for large APIs, and brings a big batch of correctness fixes across request limits, defaults, validation, and the Fiber adapter. It also raises the minimum Go version to 1.26 and includes a few intentional breaking changes, so please read the upgrade notes below.

Upgrade Notes

  • Minimum Go version is now 1.26. Dependencies have been bumped too, picking up a few vulnerability fixes (#1149)
  • Raw bodies now have default limits. Non-multipart RawBody operations (e.g. []byte uploads) now get the same default 1 MiB MaxBodyBytes and 5s BodyReadTimeout as regular bodies. Endpoints accepting larger or slower raw uploads should set these explicitly (-1 for unlimited) (#1095)
  • Multipart now honors MaxBodyBytes. An explicitly set MaxBodyBytes is now enforced on multipart requests. Multipart remains exempt from the defaults, so existing uploads keep working unless you've set a limit (#1094)
  • Overflowing default tags panic at startup. For example, int8 with default:"128" previously wrapped silently to -128; it now fails at registration (#1142)
  • Out-of-range bound tags panic at startup. For example, int8 with maximum:"500". int8, int16, uint8 and uint16 fields also now advertise minimum/maximum from their Go type, so generated specs will change (#1143)

Security Fix

A malformed Accept header such as application/json;,b caused a panic during content negotiation. On net/http-based adapters this dropped the request; on Fiber, which doesn't recover handler panics unless the recover middleware is used, it crashed the server process. This affects v2.26.0 onwards, so upgrading is recommended. (#1128)

Native Stdlib UUIDs

On Go 1.27+, fields using the new standard library uuid.UUID type are automatically documented as type: string with format: uuid, with no struct tag needed. (#1051)

Faster Compile Times

huma.Register, sse.Register and the convenience helpers (huma.Get, huma.Post, ...) now keep their generic parts tiny, so Go no longer compiles a full copy of the registration logic for every input/output pair. In a 200-operation benchmark package, build time dropped from 3.38s to 0.64s. There are no API or runtime changes. (#1115, #1117)

New Features

  • String SSE event IDs via sse.Message.IDString, for UUIDs, cursor tokens and other opaque IDs (#1086)
  • Schema can be unmarshalled from JSON, including $ref, x- extensions and nullable types, and is ready for Validate once decoded (#1144)

Validation & Defaults Fixes

  • {"type": "null"} is now validated. Previously it accepted any value, so an anyOf with a null branch skipped the constraints of its other branches (#1120)
  • Numeric request parameters which overflow the destination Go type (e.g. 300 into an int8) now return 422 instead of silently wrapping (#1096)
  • default tags on encoding.TextUnmarshaler types (e.g. a duration with default:"10s") are now applied via UnmarshalText instead of panicking (#1126)
  • Defaults are now applied to absent exploded query arrays (#1116) and missing multipart form values (#1150), and array parameters accept JSON array defaults such as default:"[\"a\",\"b\"]" (#1125)
  • Value-less query flags followed by other parameters (e.g. ?flag&foo=bar) are now detected correctly (#1097)
  • PathBuffer.Pop restores the exact offset, fixing wrong error locations after discriminator errors (#1136)
  • casing.Camel and casing.Join no longer panic or double-apply transforms when a transform removes a part (#1113)

Request Body Fixes

  • A body of exactly MaxBodyBytes is now accepted instead of returning 413 (#1131)
  • Multipart file handles are now closed after mime-type validation (#1085)

OpenAPI Fixes

  • RawBody alongside Body no longer documents an extra application/octet-stream media type (#1134)
  • The example tag on a Body field is now set as the media type example, since many tools ignore examples next to a $ref (#1101)

Adapter & Autopatch Fixes

  • humafiber: multiple Set-Cookie headers are now sent as separate header lines instead of being comma-joined (#1137)
  • humafiber (v2): autopatch now works, as its internal requests get a default Host (#1140)
  • autopatch: PATCH responses are no longer compressed twice (#1130), and $refs are resolved when making the PUT schema optional (#1080)

Docs UI & Documentation

  • Updated Scalar (1.76.0), Stoplight Elements (9.0.29) and SwaggerUI (5.34.0). Scalar no longer needs 'unsafe-eval' in its CSP, and its fonts now load (#1145)
  • Clarified that router-agnostic middleware runs after route resolution (#1088)
  • Documented that humafiber doesn't decode streamed request bodies (#1118)
  • Added SwaggerUI persistAuthorization to the DocsRendererConfig example (#1122)

What's Changed

  • fix(queryparam): correctly detect flag/bool value which is followed by a non-flag by @leonklingele in #1097
  • docs: replace Zuplo sponsorship with SerpApi by @danielgtaylor in #1106
  • feat: native support for stdlib UUIDs introduced in Go 1.27 by @leonklingele in #1051
  • perf: keep Register's generic part small to cut compile time by @iyuneev in #1115
  • fix(casing): stop transforming an index after its part is removed by @youdie006 in #1113
  • perf: keep sse.Register and convenience generic parts small by @robtme in #1117
  • fix: apply defaults to absent exploded query arrays by @Arvin-Lee in #1116
  • docs(humafiber): note streamed request bodies are not decoded by @robtme in #1118
  • docs: show SwaggerUI persistAuthorization in DocsRendererConfig example by @ize-302 in #1122
  • fix: validate the null type by @jahirulislam-forgent in #1120
  • fix: accept request bodies of exactly MaxBodyBytes by @APX403 in #1131
  • fix: Allow autopatch to resolve refs, when making the put schema optional by @lucaspopp-wbd in #1080
  • fix: don't document application/octet-stream for RawBody alongside Body by @HawkForge in #1134
  • fix: restore the exact offset in PathBuffer.Pop by @vyrnsynx in #1136
  • fix: apply default tags via TextUnmarshaler by @vulragrag-star in #1126
  • fix: reject numeric request parameters which overflow the destination Go type by @leonklingele in #1096
  • fix: reject overflowing default tags at registration by @robtme in #1142
  • fix: advertise small int bounds and reject out-of-range bound tags by @robtme in #1143
  • feat: support unmarshalling JSON into Schema by @robtme in #1144
  • chore: update docs renderers to latest versions by @robtme in #1145
  • fix(negotiation): don't panic on empty q param in SelectQValueFast by @dannyshafer in #1128
  • fix: close multipart file handles after mime-type validation by @stareezy-1 in #1085
  • fix: surface Body example tag as the media type example by @SillyZir in #1101
  • feat: support string SSE event IDs by @stareezy-1 in #1086
  • fix(autopatch): prevent double compression of PATCH responses by @Arvin-Lee in #1130
  • fix: accept JSON array defaults on array parameters by @youdie006 in #1125
  • chore: bump dependencies and minimum Go to 1.26 by @robtme in #1149
  • fix(humafiber): default the Host so autopatch works on Fiber v2 by @APX403 in #1140
  • fix(humafiber): keep multiple Set-Cookie headers separate by @APX403 in #1137
  • fix(multipart): respect MaxBodyBytes limit by @leonklingele in #1094
  • fix: respect MaxBodyBytes limit for raw bodies by @leonklingele in #1095
  • docs: clarify router-agnostic middleware runs after route resolution by @stareezy-1 in #1088
  • fix: apply the default tag to missing multipart form values by @youdie006 in #1150

New Contributors

Full Changelog: v2.39.1...v2.40.0

Don't miss a new huma release

NewReleases is sending notifications on new releases.