Skip to content

Conversation

@youta1119
Copy link

Fixes #776

@danielgtaylor danielgtaylor requested a review from Copilot March 29, 2025 17:06
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link

codecov bot commented Mar 29, 2025

Codecov Report

❌ Patch coverage is 83.33333% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.00%. Comparing base (4977a7a) to head (001826c).
⚠️ Report is 90 commits behind head on main.

Files with missing lines Patch % Lines
huma.go 83.33% 2 Missing and 1 partial ⚠️
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.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@KingkorAtMaxint
Copy link

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 ,

@wolveix wolveix self-assigned this Jan 17, 2026
@wolveix
Copy link
Collaborator

wolveix commented Jan 17, 2026

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?

@wolveix wolveix closed this Jan 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Serialization of []http.Cookie is wrong

3 participants