danielgtaylor / danielgtaylor/huma

Huma ignores custom body marshaler

Open
#789 1 comment 3 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
4.4k
Forks
285
Avg merge
40m
Merged PRs (30d)
1

Description

I can't get Huma to invoke response body custom marshalers.

Here is a minimal reproduction:

```go
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:
```console
» 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: ; 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:
```console
» 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?

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.