Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mapping Query Params in middleware #724

Open
benkawecki opened this issue Feb 10, 2025 · 2 comments
Open

Mapping Query Params in middleware #724

benkawecki opened this issue Feb 10, 2025 · 2 comments
Labels
question Further information is requested

Comments

@benkawecki
Copy link

If I define an Operation and attach some middleware to it, is there a way I can parse the body, params and path params into the operation input struct within the middleware?

A router agnostic middleware has access to the query parameters through the huma.Context. These query parameters are always returned as a string. Assuming I have a struct with a query tag which corresponds to the query parameters passed, can I bind the query parameters into that struct within the middleware?

@danielgtaylor danielgtaylor added the question Further information is requested label Feb 10, 2025
@danielgtaylor
Copy link
Owner

@benkawecki no, this isn't currently possible as the parsing happens after the middlewares have run and Huma doesn't publicly expose the param parsing logic.

What specifically are you trying to do?

@benkawecki
Copy link
Author

So some background on the request. We have a multi-tenancy application where data is separated into namespaces. Authorization broken down into read or write by tenancy. For example: a given user may have read on namespace foo and namespace bar. Authorization is done via a router agnostic middleware. Since access is tenancy specific we typically have to introspect the request in some way to determine what the user is attempting to access when authorizing.

This leads to two scenarios we are running into problems with.

  1. Authorizing List operations.
  2. Authorizing Post operations for resource creation.

Authorizing List operations

We have a shared parameter definition for passing namespaces in a list request.

type NamespacesParam struct {
	Namespaces []string `query:"namespaces" required:"true"`
}

For our list routes our authorization middleware checks each namespace the user is attempting to access and will reject the request is the user is accessing a namespace they don't have access to. When we get the namespaces header using ctx.Query("namespaces") it returns a string. This is fine, but since we already have a single definition for namespaces I would love to be able to reuse that logic, rather than having to write custom logic for parsing it into a []string.

I would love something like:

func middleware(ctx huma.Context, next func(huma.Context)) {
        var nsParam NamespaceParam 
        err := huma.ParseParam(ctx, &nsParam)
        ...
}

Authorizing Post Operations

We also have some post operations we need to authorize. Post operations create a resource in a single namespace. The route for this is currently: POST api/resource/, and the resource definition may look something like this:

type Resource struct {
	Namespace string `json:"namespace" required:"true`
        ResourceID int `json:"resourceID"`
	Value     int    `json:"value"`
}

The problem with this approach is that I need to fully parse the request inorder to determine the namespace the user wants to create the resource within. I see a couple solutions to this problem:

  1. We move the namespace into the path.
  2. We attach some authorizer object into the context and push the authorization into the request handler.
  3. We parse the request object in the middleware and introspect the namespace attribute.

Moving the namespace into the path is probably the path we will go. Option 2 feels like a large mixing of responsibilities and introduces alot of overhead for testing as now the handler is reliant on some Authorizer interface. Option3 has a lot of potential issues.

That being said, if there was no other option but to parse the request within the middleware, is there a function we could call?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants