fix: serialization of []http.Cookie#778
Conversation
There was a problem hiding this comment.
Pull Request Overview
This PR fixes the serialization issue for []http.Cookie by skipping header processing for cookie slices. Key changes include:
- Adding a new field (ShouldSkip) to headerInfo to mark headers that should not be serialized.
- Introducing a lambda in findHeaders to detect cookie slices and mark them accordingly.
- Adjusting recursive processing in _findInType to respect the new skip flag.
Comments suppressed due to low confidence (1)
huma.go:413
- [nitpick] Consider renaming 'resolved' to a more descriptive name such as 'headerFound' to better convey its purpose.
resolved := false
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #778 +/- ##
==========================================
- Coverage 93.10% 93.00% -0.11%
==========================================
Files 23 23
Lines 5296 5301 +5
==========================================
- Hits 4931 4930 -1
- Misses 313 317 +4
- Partials 52 54 +2 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
Can this be merged and released please? This is a huge bug and it's stopping us from implement a cookie based authentication. When we try to set multiple cookies using the slices syntax, it's setting the first one as whole. Then it adds another Set-Cookie with all the cookies combined by |
|
Thank you so much for this contribution @youta1119! Unfortunately, while this does fix the cookie issue, it doesn't actually resolve the underlying problem which is that a slice of structs (of any type) will experience the same issue. Take a look at this example: package main
import (
"context"
"fmt"
"net/http"
"github.com/danielgtaylor/huma/v2"
"github.com/danielgtaylor/huma/v2/adapters/humachi"
"github.com/danielgtaylor/huma/v2/humacli"
"github.com/go-chi/chi/v5"
_ "github.com/danielgtaylor/huma/v2/formats/cbor"
)
// Options for the CLI.
type Options struct {
Port int `help:"Port to listen on" short:"p" default:"8888"`
}
// GreetingInput represents the greeting operation request.
type GreetingInput struct {
Name string `path:"name" maxLength:"30" example:"world" doc:"Name to greet"`
Foo http.Cookie `cookie:"foo"`
}
// GreetingOutput represents the greeting operation response.
type GreetingOutput struct {
SetCookie []*CookieExampleStruct `header:"Set-Cookie"`
Body struct {
Message string `json:"message" example:"Hello, world!" doc:"Greeting message"`
}
}
type CookieExampleStruct struct {
Name string
Value string
}
func main() {
// Create a CLI app which takes a port option.
cli := humacli.New(func(hooks humacli.Hooks, options *Options) {
// Create a new router & API
router := chi.NewMux()
api := humachi.New(router, huma.DefaultConfig("My API", "1.0.0"))
// Register GET /greeting/{name}
huma.Register(api, huma.Operation{
OperationID: "get-greeting",
Summary: "Get a greeting",
Method: http.MethodGet,
Path: "/greeting/{name}",
}, func(ctx context.Context, input *GreetingInput) (*GreetingOutput, error) {
fmt.Println("cookie foo is", input.Foo.Value)
resp := &GreetingOutput{}
resp.Body.Message = fmt.Sprintf("Hello, %s!", input.Name)
resp.SetCookie = []*CookieExampleStruct{
{
Name: "foo",
Value: "bar",
},
{
Name: "zoo",
Value: "zar",
},
}
return resp, nil
})
// Tell the CLI how to start your router.
hooks.OnStart(func() {
http.ListenAndServe(fmt.Sprintf(":%d", options.Port), router)
})
})
// Run the CLI. When passed no commands, it starts the server.
cli.Run()
}Even with this PR, this happens: ❯ curl --dump-header - -b "foo=bar" http://localhost:8888/greeting/me
HTTP/1.1 200 OK
Content-Type: application/json
Link: </schemas/GreetingOutputBody.json>; rel="describedBy"
Name: zoo
Set-Cookie: &{foo bar}
Set-Cookie: &{zoo zar}
Value: zar
Date: Sat, 17 Jan 2026 19:24:28 GMT
Content-Length: 93
{"$schema":"http://localhost:8888/schemas/GreetingOutputBody.json","message":"Hello, me!"}I was able to instead resolve this issue by not automatically using struct fields for header names. Relevant PR here: #943. @KingkorAtMaxint that doesn't sound like the same problem. Would you mind opening a separate issue, please? |
Fixes #776