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

Allow parameter expansion into multiple query parameters #625

Open
lucianoRM opened this issue Sep 22, 2023 · 0 comments
Open

Allow parameter expansion into multiple query parameters #625

lucianoRM opened this issue Sep 22, 2023 · 0 comments

Comments

@lucianoRM
Copy link

lucianoRM commented Sep 22, 2023

I am still doubting if I should post this issue here or in https://github.com/OpenFeign , since I think this is actually a Feign limitation.
However, Feign allows the configuration of Encoders, which ReactiveFeign does not. So, this solution: OpenFeign/feign#254 is not possible here.

Issue

I need to be able to expand a single parameter into multiple query parameters.
Consider the following interface method:

@GetMapping(value = "/things")
Mono<List<String>> getPaginated(final @PageRequestParam PageRequest pageRequest);

where

public class PageRequest {
 private int offset; 
 private int limit;
}

Attempted solutions

Solution 1: AnnotatedParameterProcessor

I can create a new AnnotatedParameterProcessor that knows how to handle @PageRequestParam annotations.
Here, I can modify the RequestTemplate and include the required query parameters. The issue is that I can only use templating since the AnnotatedParameterProcessor does not know about the actual values provided when making the request.

On top of that, parameter templating only let's me use the name of the parameter to resolve. It does not allow for attribute accessing or any expression language.

I could do something like:

public class PageRequestParameterProcessor implements AnnotatedParameterProcessor {

    @Override
    public boolean processArgument(AnnotatedParameterContext context, Annotation annotation, Method method) {
        ...
        date.template().query("offset", "{pagerRequest.offset}")
        data.template().query("limit", "{pageRequest.limit}");
    }

Solution 2: AnnotatedParameterProcessor + ParameterExpander

I could also configure a parameter expander to transform from PageRequest into the values I need.
The issue here is that the RequestTemplate only allows to configure one expander per method index. Then, my PageRequest can only be expanded once into an String.
It would be great if the Expander is called once every time the template has to be resolved and providing additional context for the resolution.

Here: reactivefeign.methodhandler.PublisherClientMethodHandler#buildRequest. Instead of building an static Substitutions object from the provided arguments, call an Expander every time but with additional context like that lets the expander know what the object is being expanded for (query params, body, header, etc).

Solution 3: AnnotatedParameterProcessor + ParameterExpander into multiple query params

Since the parameter Expander will only be called once for my PageRequest, I can "hack" the String response and do something like:

public class PageRequestParameterProcessor implements AnnotatedParameterProcessor {

    @Override
    public boolean processArgument(AnnotatedParameterContext context, Annotation annotation, Method method) {
        ...
         data.indexToExpander().put(parameterIndex, value -> {
            final PageRequest pageRequest = (PageRequest) value;
            "%d&offset=%d".formatted(pageRequest.getLimit(), pageRequest.getOffset());
        });
        date.template().query("offset", "{pageRequest}")
    }

But then the value gets encoded and the special chars like & and = are replaced.

Solution 4: AnnotatedParameterProcessor + mark the parameter as QueryMap

I could also mark the parameter as a query map within my processor by calling:

data.queryMapIndex(parameterIndex)

And that will cause Feign to expand it when creating the query parameters. But this also can only be done once.
If I have an actual @QueryMap in my method they will conflict with each other.


I don't know. I am kind of lost here. Is this something that can be done?

Thanks

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

No branches or pull requests

1 participant