Open
Description
I can't get Huma to invoke response body custom marshalers.
Here is a minimal reproduction:
package main
import (
"context"
"encoding/json"
"net/http"
"github.com/danielgtaylor/huma/v2"
"github.com/danielgtaylor/huma/v2/adapters/humago"
"github.com/google/uuid"
"github.com/mr-tron/base58"
)
func main() {
router := http.NewServeMux()
api := humago.New(router, huma.DefaultConfig("Marshal Test", "1"))
huma.Get(api, "/auto", handler)
huma.Get(api, "/manual", manualMarshal)
http.ListenAndServe(":8081", router)
}
type Output struct {
Body Body
}
type Body struct {
ID uuid.UUID `json:"id"`
Message string `json:"message"`
}
type Output2 struct {
Body []byte
}
func handler(ctx context.Context, i *struct{}) (*Output, error) {
output := Output{
Body: Body{
ID: uuid.New(),
Message: "Hello",
},
}
return &output, nil
}
func manualMarshal(ctx context.Context, i *struct{}) (*Output2, error) {
body := Body{
ID: uuid.New(),
Message: "Hello",
}
bodyJSON, err := json.Marshal(body)
return &Output2{Body: bodyJSON}, err
}
// Convert ID from UUID to base58 string
func (b Body) MarshalJSON() ([]byte, error) {
type BodyAlias Body
type BodyJSON struct {
ID string `json:"id"`
BodyAlias
}
idB58, err := uuidToBase58(b.ID)
if err != nil {
return nil, err
}
return json.Marshal(BodyJSON{
ID: idB58,
BodyAlias: BodyAlias(b),
})
}
func uuidToBase58(id uuid.UUID) (string, error) {
binID, err := id.MarshalBinary()
if err != nil {
return "", err
}
return base58.Encode(binID), nil
}
Basically, I have a custom marshaler that converts the UUID ID field to a base58-encoded string, and there are two handlers: one relying on Huma to invoke the custom marshaler (/auto
), and one invoking the custom marshaler manually and returning a json-encoded byte array (/manual
).
Calling the handler whose output body has a custom marshaler ignores the marshaler and returns unencoded UUIDs:
» restish :8081/auto
HTTP/1.1 200 OK
Content-Length: 116
Content-Type: application/json
Date: Fri, 04 Apr 2025 14:14:49 GMT
Link: </schemas/Body.json>; rel="describedBy"
{
$schema: "http://localhost:8081/schemas/Body.json"
id: "abd2feee-569b-4a47-b360-9bfdfcf456de"
message: "Hello"
}
Calling the handler that manually marshals its output does encode the ID to a base58 string, demonstrating that the custom marshaler works:
» restish :8081/manual
HTTP/1.1 200 OK
Content-Length: 49
Content-Type: text/plain; charset=utf-8
Date: Fri, 04 Apr 2025 14:14:53 GMT
{"id":"QS6Y2UJyGKk4PGpHn7d2Bf","message":"Hello"}
How can I get Huma to recognize and invoke custom marshalers on the output body or sub-structures thereof?
Metadata
Metadata
Assignees
Labels
No labels