eclipse / microprofile-rest-client

MicroProfile Rest Client
Apache License 2.0
141 stars 72 forks source link

How to use MicroProfile Rest Client with many parameters #286

Open jdang67 opened 4 years ago

jdang67 commented 4 years ago

Hi Everyone,

I want to use MicroProfile Rest Client. However, I need to talk to the endpoint like the following:

http://localhost:8083/serviceName/sub/abc?p1=val1&p2=val2&p3=val3@p4=val4

and here is the the base URL: http://localhost:8083


    @GET
    @Path("/serviceName/sub/abc/")
    @Produces(MediaType.APPLICATION_JSON)
    public String test(@DefaultValue("val1") @QueryParam("p1") String p1,
                                   @DefaultValue("val2")  @QueryParam("p2") String p2,
                                   @DefaultValue("val3")  @QueryParam("p3") String p3,
                                   @QueryParam("val4") String p4);

Using the URL directly always returns data while using rest-client throws exception:

RESTEASY004655: Unable to invoke request: org.apache.http.conn.HttpHostConnectException: Connect to localhost:8003 [localhost/127.0.0.1, localhost/0:0:0:0:0:
0:0:1] failed: Connection refused: connect

Anything wrong with the way I use the MicroProfile Rest Client?

thanks,

Jdang

andymc12 commented 4 years ago

Hi @jdang67 , I think there may be a typo in your configured base URI. The error message says it is trying to connect on port 8003, but you said that the service was listening on port 8083. You’ll probably just need to change the base URI in you MP Config or builder code. Other than that, everything else looks good to me.

HTH, Andy

jdang67 commented 4 years ago

Hi Andymc12,

Yes, I made a mistake on the port #. However, it complains about the input param. Looks like the framework fails to send the "service" parameter?

// actual request that works
http://localhost:8083/geoserver/omi/ows?service=WFS&version=2.0.0&request=GetFeature&count=10&outputFormat=application%2fjson&exceptions=application%2fjson&propertyName=mmsi%2clat%2clon%2cdtg%2cimo%2ccall_sign%2cvessel_name&typeName=omi%3aais-enriched-stream&CQL_FILTER=(DWITHIN(geom%2c+POINT+(39.5783+121.2671)%2c+500%2c+Meters))

 <ows:Exception exceptionCode="InvalidParameterValue" locator="service">
    <ows:ExceptionText>No service: ( ows )</ows:ExceptionText>
  </ows:Exception>

And this is the actual interface

  @GET
    @Path("/geoserver/omi/ows/")
    @Produces(MediaType.APPLICATION_JSON)
    public String getVesselsNearBy(@DefaultValue("WFS") @QueryParam("service") String service,
                                   @DefaultValue("2.0.0")  @QueryParam("version") String version,
                                   @DefaultValue("GetFeature")  @QueryParam("request") String request,
                                   @DefaultValue("10")  @QueryParam("count") String count,
                                   @DefaultValue("application/json")  @QueryParam("outputFormat") String outputFormat,
                                   @DefaultValue("application/json")  @QueryParam("exceptions") String exceptions,
                                   @DefaultValue("mmsi,lat,lon,dtg,imo,call_sign,vessel_name") @QueryParam("propertyName") String propertyName,
                                   @DefaultValue("omi:ais-enriched-stream")  @QueryParam("typeName") String typeName,
                                   @QueryParam("CQL_FILTER") String cqlFilter );

In this case, the only parameter that can be changed is the CQL_FILTER, the rest should be static. How do I check the actual request that sends to the server? What should be on the base URL, path?

thanks,

Jdang

andymc12 commented 4 years ago

What value are you passing for the service parameter on the client side? @DefaultValue is only required to work on the server side (JAX-RS) - though implementations could make use of them in non-portable ways (for example, they could convert a null parameter to the value specified in the annotation). Supporting @DefaultValue sounds like a good feature request for the spec...

I've found that the best way to see what is sent from the client is to use a utility like tcptunnel ( https://github.com/vakuum/tcptunnel ). With this tool, you basically create a logging proxy - for example: tcptunnel --local-port 10001 --remote-host localhost --remote-port 8083 --stay-alive --log will listen on port 10001 and then forward anything it receives to localhost port 8083 - and log the request and response in the console.

Then you can change your baseURI in the MP Rest Client to point to localhost:10001 and you can see exactly what is sent and what is received.

Different MP Rest Client implementations may also have different tracing options to see what exactly is sent, but generally I've found this approach to work fairly consistently - iirc, it does have problems with SSL/HTTPS though...

HTH, Andy

jdang67 commented 4 years ago

Andy,

The value of service param is "WFS" and currently supply by the @DefaultValue("WFS").

John

andymc12 commented 4 years ago

John,

Are you using the same interface for both the client and the server? The @DefaultValue("WFS") will only take effect on the server - and the default value ("WFS") should only be used if there is no query parameter from the client request.

What I suspect is happening is that when you invoke the client, you may be passing null to the client interface parameter, expecting that the client implementation of the interface will then use the default value, but that is not currently a spec-defined behavior. Instead, what I suspect would happen is that the client implementation will generate a request that includes a query parameter like this: ?service=null If I'm right, then I think "null" (the string, not an actual null value) would be passed to the JAX-RS resource on the server side - and that would likely result in an error.

The tcptunnel approach should help determine what is actually sent to the server.

HTH, Andy

jdang67 commented 4 years ago

Andy,

Sorry for the late response since I have to implement the HttpClient by myself. You are right, I have to pass all null for params which are always the same. I cannot pass only the param that requires. Looks like MicroProfile Rest Client has a problem with design?

John

andymc12 commented 4 years ago

I would look at it as an opportunity to improve the design. ;-)

It is probably too late to add support for @DefaultValue in the 2.0 release, but I think it is a good feature request.

One of the problems with supporting @DefaultValue is that the value in the annotation must be a String. That works fine for types that are easily initialized from a string value, but no so much for custom types, etc. The server side already supports ParamConverters that would convert strings to objects - so maybe the Rest Client would need to support them as well for converting default values to non-string parameters.