micronaut-core icon indicating copy to clipboard operation
micronaut-core copied to clipboard

Customizing x-www-form-urlencoded request body in HTTP Client

Open Kidlike opened this issue 2 years ago • 2 comments

Problem

I'm trying to make an x-www-form-urlencoded HTTP request, with attribute names that don't follow Java's conventions, because of a 3rd party that uses snake_case.

I try to illustrate this in the following code snippet, by using @JsonProperty("some_attribute") (note: this is not working).

Link to sample repo: https://github.com/Kidlike/mn-form-urlencoded-jackson

import com.fasterxml.jackson.annotation.JsonProperty;
import io.micronaut.core.annotation.Introspected;
import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.Body;
import io.micronaut.http.annotation.Post;
import io.micronaut.http.client.annotation.Client;
import reactor.core.publisher.Mono;

@Client("/echo")
public interface SampleClient {

    @Post(produces = MediaType.APPLICATION_FORM_URLENCODED, consumes = MediaType.APPLICATION_JSON)
    Mono<SampleDto> echo(@Body SampleDto sampleDto);

    @Introspected
    class SampleDto {

        @JsonProperty("some_attribute")
        private String someAttribute;

        public SampleDto() {
        }

        public SampleDto(String someAttribute) {
            this.someAttribute = someAttribute;
        }

        public String getSomeAttribute() {
            return someAttribute;
        }

        public void setSomeAttribute(String someAttribute) {
            this.someAttribute = someAttribute;
        }
    }
}

Investigation

After some digging in Micronaut's source code, I found that this media type has special handling: https://github.com/micronaut-projects/micronaut-core/blob/c7731627a9856157809aa0a53840ab7154f3fe6f/http-client/src/main/java/io/micronaut/http/client/netty/DefaultHttpClient.java#L1673-L1682

Then buildFormDataRequest is called: https://github.com/micronaut-projects/micronaut-core/blob/c7731627a9856157809aa0a53840ab7154f3fe6f/http-client/src/main/java/io/micronaut/http/client/netty/DefaultHttpClient.java#L2274-L2282

And in the end, BeanMap.of: https://github.com/micronaut-projects/micronaut-core/blob/c7731627a9856157809aa0a53840ab7154f3fe6f/core/src/main/java/io/micronaut/core/beans/BeanMap.java#L45-L49

Workaround

According to the above, this means that the only way to manipulate in any way the parameters of this x-www-form-urlencoded request, are by the real field members of the body class. Or more specifically with this adjustment:

public String getSome_attribute() {
    return someAttribute;
}

This works, but obviously the name of the getter is very weird, and does not follow modern java's naming conventions. Also it's not possible to hide it, because it has to be public in order for it to be serialized.

Suggestion

Since Jackson annotations seem to be respected in the request body of controllers that consume x-www-form-urlencoded requests, it would be sensible to also do it for the outgoing requests (http client). Of course I don't know if this is technically feasible; I guess it depends on the capabilities of Jackson.

Kidlike avatar Jul 31 '22 08:07 Kidlike

#1853

yawkat avatar Aug 01 '22 08:08 yawkat

#1853

thanks for this... I actually searched and couldn't find anything :(

Kidlike avatar Aug 01 '22 08:08 Kidlike

i'm running into this after upgrading to 4.1.1. i was getting the right behavior in 3.10

gad2103 avatar Oct 03 '23 19:10 gad2103

I can confirm that this used to work for Micronaut 3.4.3 by either annotating with @JsonProperty or adjusting the names of the getters e.g. the getter for the field private String grantType had to be getGrant_type() in order to serialize to grant_type in the URL form.

For Micronaut 4.2 i can confirm that this behavior actually doesn't work anymore so the only workaround is to use a Map instead as there is a dedicated execution branch for this.

I'd appreciate if you'd fix this e.g. by a @FormProperty annotation as you've mentioned in a different thread.

renepanke avatar Nov 23 '23 08:11 renepanke

I think the label "workaround available" can be added.

renepanke avatar Nov 25 '23 15:11 renepanke