这是indexloc提供的服务,不要输入任何密码
Skip to content

Router-agnostic middleware example does not set response header as expected #355

@GidVeo

Description

@GidVeo

Hi - and thanks for this amazing project!

I am working my way through the docs and noticed that this example
https://huma.rocks/features/middleware/#router-agnostic

Implemented in a minimal example using the greetings tutorial code (with Chi replaced by the standard library router) does not actually set a response header:

package main

import (
	"context"
	"fmt"
	"net/http"

	"github.com/danielgtaylor/huma/v2"
	"github.com/danielgtaylor/huma/v2/adapters/humago"
)

// GreetingOutput represents the greeting operation response.
type GreetingOutput struct {
	Body struct {
		Message string `json:"message" example:"Hello, world!" doc:"Greeting message"`
	}
}

func MyMiddleware(ctx huma.Context, next func(huma.Context)) {
	next(ctx)
	ctx.SetHeader("My-Custom-Header", "Hello, world!")
}

func main() {
	// Create a new router & API.
	router := http.NewServeMux()
	api := humago.New(router, huma.DefaultConfig("My API", "1.0.0"))
	api.UseMiddleware(MyMiddleware)

	// Register GET /greeting/{name} handler.
	huma.Get(api, "/greeting/{name}", func(ctx context.Context, input *struct {
		Name string `path:"name" maxLength:"30" example:"world" doc:"Name to greet"`
	}) (*GreetingOutput, error) {
		resp := &GreetingOutput{}
		resp.Body.Message = fmt.Sprintf("Hello, %s!", input.Name)
		return resp, nil
	})

	// Start the server!
	http.ListenAndServe("127.0.0.1:8888", router)
}
curl http://localhost:8888/greeting/world -v 2>&1 | grep "My-Custom-Header"
[ blank ]

However, when I moveSetHeader before calling next() it appears to work as intended:

func MyMiddleware(ctx huma.Context, next func(huma.Context)) {
	ctx.SetHeader("My-Custom-Header", "Hello, world!")
	next(ctx)
}
curl http://localhost:8888/greeting/world -v 2>&1 | grep "My-Custom-Header"
< My-Custom-Header: Hello, world!

However that seems to defeat the purpose of the example.. I am not sure if this is the intended behavior or the docs are incorrect?

It appears this functionality is meant to mimic FastAPI/Starlette middleware such as this one where response = await call_next(request) continues the request and the header data is set after the other middlewares and route handler have returned.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingdocumentationImprovements or additions to documentation

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions