You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@juneau.apache.org by sblackmon <sb...@apache.org> on 2017/03/20 06:55:10 UTC

Advice regarding Juneau RestClient, RestCall, Serializers, best practices

Hello,

I’m working on a class that uses RestClient to implement several contextually related methods.

Each method has a POJO describing the request, and a POJO describing the response (some methods return a list of the response POJOs).

As I understand from reading docs for 6.1.1-incubating-SNAPSHOT, while a RestServlet may bind multiple Serializers and Parsers, a RestClient may only bind one of each.

So i guess that means I need to instantiate a different RestClient for each supported method, or bind a single custom Serializer and Parser that can handle all of the request and response objects?

I notice that it’s easy to create and re-use one HttpClient across RestClients, and there’s presumably no problem reusing all the member objects of RestClient, so there should be minimal performance overhead to holding more than one on the class, or even creating a new RestClient for every call is I don’t close the connection.

I also am thinking that a new method on RestClient that allowed you to doGet from an request POJO, and have it converted into parameters (using BeanMap?) would help make this easier.

Also wondering whether type erasure will limit the flexibility of restCall.getResponse(T), when the result comes back as a List.  In my own APIs I always return an Object but a top-level array is fairly common practice.

Anyway, I’ve pushed some early work to this branch, and I’d be interested in feedback as I work through this, whether it’s on the right track to minimize code complexity and maximize performance for what we’re trying to do.

I’m not yet to the point of running any integration tests using this new implementation but hope to be soon.

https://github.com/apache/incubator-streams/compare/master...steveblackmon:STREAMS-496

Thanks in advance,
Steve (Streams)

Re: Advice regarding Juneau RestClient, RestCall, Serializers, best practices

Posted by James Bognar <ja...@salesforce.com>.
Hi Steve,

So there's already a @Remoteable annotation that can be applied to
Classes/Interfaces/Methods to fine-tune which methods are visible for
proxying.  Maybe add to this annotation?

@Remoteable(path = "/statuses")
public interface Statuses {
  public List lookup(StatusesLookupRequest parameters);
}

I've added a confluence design document to discuss further.  Feel free to
edit...
https://cwiki.apache.org/confluence/display/JUNEAU/Remote+proxy+REST+methods


On Wed, Mar 22, 2017 at 3:01 PM, sblackmon <sb...@apache.org> wrote:

>
> Regarding the improvements to proxies, great to hear that is an area of
> active development. I’ll be watching for a new snapshot adding that method
> that would let me derive multiple proxy interfaces from a single rest
> client by specifying a path for each.
>
> Since we’re looking that this capability right now, would be it a stretch
> to attach the @RestMethod or similar annotation with a path attribute
> directly to the interface class?
>
> @RestMethod(name = "statuses", path = "/statuses/*")
> public interface Statuses {
>   public List lookup(StatusesLookupRequest parameters);
> }
>
> This way the interface describes each endpoint at a specific path, and
> where that path resides relative to a root URL.
>
> Then a top-level accessor class would define the root URL and hold one
> instance of each interface it exposed:
>
> public class Twitter {
>   private String rootUrl = “https://api.twitter.com/v1";
>   private RestClient client = new RestClientBuilder()
>     .serializer(JsonSerializer.class)
>     .parser(JsonParser.class)
>     .authorization( … whatever … )
>     .rootUrl(rootUrl)
>     .build();
>   public Statuses statuses = client.getRemoteableProxy(Statuses.class);
>   // etc for the other ~30 endpoints
> }
>
> Now any class that has a pointer to a Twitter could do the following
> synchronously:
>
> StatusesLookupRequest statusesLookupRequest = new StatusesLookupRequest().withId(new
> ArrayList(“123”,”456”));
> List tweets = twitter.statuses.lookup(statusesLookupRequest);
>
> This seems to me like a killer scheme for mapping and wrapping http apis
> for JVM that we could apply across most of the data providers in Streams.
>
> Cheers,
> Steve
>
> P.S. for a future thread, how about asynchronous access?
> On March 22, 2017 at 11:17:36 AM, James Bognar (
> james.bognar@salesforce.com(mailto:james.bognar@salesforce.com)) wrote:
>
> > *This makes a lot of sense to me. If it’s possible to also allow for an
> > in-line override of Serializer or Parser, that would limit the number of
> > RestClients our provider classes need to create (to 1).*
> >
> > Will do.
> >
> >
> > *And you can also specify arrays...getResponse(MyBean[].class). This is
> > perfect. I remember now seeing the Type,Type… method in the release notes
> > and will try it out right away. Of course, I’m hoping that
> RemoteableProxy
> > can be used across the board, if so we won’t need implementation classes
> > that would have to do this at all.*
> >
> > I need to update the javadocs on the RestClient.getResponse(Type,
> Type...)
> > method. It's not clear from the docs how to use it. For now, just refer
> > to the Parser#parse(Type,Type...) for how that works for maps and
> > collections.
> >
> > If you're interested in the remoteable proxies, you'll probably be
> > interested in what I've been working on this week...adding interface
> > proxies using @RestMethod. It's a simplified way to define them without
> > having to use the RemoteableServlet. Instead, you just define a
> > @RestMethod(name="PROXY") method with an interface return type, like
> so....
> >
> > /**
> > * [PROXY /*]
> > * Return a proxy interface to IAddressBook.
> > */
> > @RestMethod(name="PROXY", path="/myproxy/*")
> > public IAddressBook getProxy() {
> > return addressBook;
> > }
> > On the client side, you get the proxy using RestClient like so....
> >
> > IAddressBook ab = client.getRemoteableProxy(IAddressBook.class,
> > "/addressBook/myproxy");
> > Under-the-covers, a method call is simply a POST with parameters and
> > returned object marshalled in the HTTP request and response bodies, and
> the
> > individual methods are addressed using the method signature...e.g....
> > POST /addressBook/myproxy/callMyMethod(java.lang.String,boolean)
> >
> >
> >
> >
> >
> >
> >
> > On Wed, Mar 22, 2017 at 11:20 AM, sblackmon wrote:
> >
> > > Thanks James. Comments below.
> > > On March 20, 2017 at 11:48:16 AM, James Bognar (
> > > james.bognar@salesforce.com) wrote:
> > >
> > > Hi Steve!
> > >
> > > I'm in training today, so my responses may not be prompt.
> > >
> > > Heads up....in 6.2.0 (what I'm working on now, currently labeled
> 6.1.1),
> > > I'm revamping the RestClient code to use builders just like I did for
> the
> > > serializers and parsers in 6.1.0. So now's a good time for suggested
> > > changes! I think the new design makes it considerably easier to
> understand
> > > and reuse HttpClients or HttpClientBuilders.
> > >
> > > You're correct that a RestClient only uses a single serializer/parser
> > > pair. The thoughts were...
> > > 1) You avoid having to specify the Accept and Content-Type on the
> RestCall
> > > object.
> > > 2) Typical real-world scenario would be that you're only interested in
> > > working in a particular language.
> > >
> > > If you anticipate needing support for multiple languages, it won't be
> > > difficult to add. Most likely with a 'default' language, and if you
> want
> > > to use one of the others, you need to do...
> > > RestClient.doX().setAccept("text/foo").setContentType("
> > > text/foo").getResponse(X);
> > >
> > > Let me know if you want this.
> > > This makes a lot of sense to me. If it’s possible to also allow for an
> > > in-line override of Serializer or Parser, that would limit the number
> of
> > > RestClients our provider classes need to create (to 1).
> > >
> > >
> > >
> > > *I also am thinking that a new method on RestClient that allowed you to
> > > doGet from an request POJO, and have it converted into parameters
> (using
> > > BeanMap?) would help make this easier.*
> > > I'm not sure I understand. Can you provide a code example? (or is it in
> > > the branch already?)
> > > Here’s a specific use case from STREAMS-496.
> > >
> > > We have an interface that describes the behavior of an external REST
> > > endpoint:
> > >
> > > https://github.com/steveblackmon/incubator-streams/blob/STREAMS-496/
> > > streams-contrib/streams-provider-twitter/src/main/
> java/org/apache/streams/
> > > twitter/api/Statuses.java
> > >
> > > The module contains POJOs for the inputs and outputs of these
> endpoints,
> > > generate from jsonschemas.
> > >
> > > https://github.com/steveblackmon/incubator-streams/blob/STREAMS-496/
> > > streams-contrib/streams-provider-twitter/src/main/
> > > jsonschema/org/apache/streams/twitter/api/StatusesLookupRequest.json
> > >
> > > As I understand, If the third-party endpoints worked on the ‘post with
> > > json to get json’ model, then we could use juneau’s RemotableProxy
> > > capability to execute these transactions with just the POJOs and the
> > > interface, no implementation of the interface required! Very cool...
> > > However, the third-party endpoints actually use a ‘get with a bunch of
> > > params to get json’ model, and defining the interface methods as a
> chain of
> > > 10+ primitives, most of which are optional, is ugly and difficult to
> use in
> > > java. I’d much prefer to define the interface using a ‘one POJO in, one
> > > POJO out’ (like in the links above), and use the fluent builders on
> those
> > > beans to craft the request objects.
> > >
> > > My suggestion is to add a generic swap capability usable by RestClient
> or
> > > RemoteableProxy that can translate a single (probably flat) POJO
> argument
> > > into get parameters transparently, so that remotableproxy using get
> > > requests with complex argument structures can be as easy to code and
> easy
> > > to read as those using post requests with payloads.
> > >
> > > If this sounds good to you, put it in JIRA and I’ll take a shot at the
> > > implementation.
> > >
> > >
> > >
> > > *Also wondering whether type erasure will limit the flexibility of
> > > restCall.getResponse(T), when the result comes back as a List. In my
> own
> > > APIs I always return an Object but a top-level array is fairly common
> > > practice.*
> > >
> > > The getResponse(Type,Type...) method should allow you to reconstruct
> > > parameterized lists and maps.
> > > For example:
> > > getResponse(LinkedList.class,MyBean.class) - A list of beans.
> > > getResponse(HashMap.class,String.class,LinkedList.class,MyBean.class)
> - A
> > > hashmap with string keys and list of beans values.
> > >
> > > And you can also specify arrays...getResponse(MyBean[].class).
> > > This is perfect. I remember now seeing the Type,Type… method in the
> > > release notes and will try it out right away. Of course, I’m hoping
> that
> > > RemoteableProxy can be used across the board, if so we won’t need
> > > implementation classes that would have to do this at all.
> > >
> > >
> > >
> > > Refer to the Parser#parse(Object input, Type type, Type...args)
> javadocs
> > > for info. The RestCall#getResponse() should act the same.
> > >
> > >
> > >
> > > On Mon, Mar 20, 2017 at 2:55 AM, sblackmon wrote:
> > >
> > > > Hello,
> > > >
> > > > I’m working on a class that uses RestClient to implement several
> > > > contextually related methods.
> > > >
> > > > Each method has a POJO describing the request, and a POJO describing
> the
> > > > response (some methods return a list of the response POJOs).
> > > >
> > > > As I understand from reading docs for 6.1.1-incubating-SNAPSHOT,
> while a
> > > > RestServlet may bind multiple Serializers and Parsers, a RestClient
> may
> > > > only bind one of each.
> > > >
> > > > So i guess that means I need to instantiate a different RestClient
> for
> > > > each supported method, or bind a single custom Serializer and Parser
> > > that
> > > > can handle all of the request and response objects?
> > > >
> > > > I notice that it’s easy to create and re-use one HttpClient across
> > > > RestClients, and there’s presumably no problem reusing all the member
> > > > objects of RestClient, so there should be minimal performance
> overhead
> > > to
> > > > holding more than one on the class, or even creating a new RestClient
> > > for
> > > > every call is I don’t close the connection.
> > > >
> > > > I also am thinking that a new method on RestClient that allowed you
> to
> > > > doGet from an request POJO, and have it converted into parameters
> (using
> > > > BeanMap?) would help make this easier.
> > > >
> > > > Also wondering whether type erasure will limit the flexibility of
> > > > restCall.getResponse(T), when the result comes back as a List. In my
> own
> > > > APIs I always return an Object but a top-level array is fairly common
> > > > practice.
> > > >
> > > > Anyway, I’ve pushed some early work to this branch, and I’d be
> > > interested
> > > > in feedback as I work through this, whether it’s on the right track
> to
> > > > minimize code complexity and maximize performance for what we’re
> trying
> > > to
> > > > do.
> > > >
> > > > I’m not yet to the point of running any integration tests using this
> new
> > > > implementation but hope to be soon.
> > > >
> > > > https://github.com/apache/incubator-streams/compare/
> > > > master...steveblackmon:STREAMS-496
> > > >
> > > > Thanks in advance,
> > > > Steve (Streams)
> > >
> > >
> > >
> > >
> > > --
> > > James Bognar
> > >
> >
> >
> >
> > --
> > James Bognar
>
>


-- 
James Bognar

Re: Advice regarding Juneau RestClient, RestCall, Serializers, best practices

Posted by sblackmon <sb...@apache.org>.
 
Regarding the improvements to proxies, great to hear that is an area of active development. I’ll be watching for a new snapshot adding that method that would let me derive multiple proxy interfaces from a single rest client by specifying a path for each.

Since we’re looking that this capability right now, would be it a stretch to attach the @RestMethod or similar annotation with a path attribute directly to the interface class?  

@RestMethod(name = "statuses", path = "/statuses/*")
public interface Statuses {  
  public List lookup(StatusesLookupRequest parameters);
}

This way the interface describes each endpoint at a specific path, and where that path resides relative to a root URL.  

Then a top-level accessor class would define the root URL and hold one instance of each interface it exposed:

public class Twitter {
  private String rootUrl = “https://api.twitter.com/v1";  
  private RestClient client = new RestClientBuilder()  
    .serializer(JsonSerializer.class)
    .parser(JsonParser.class)  
    .authorization( … whatever … )
    .rootUrl(rootUrl)  
    .build();
  public Statuses statuses = client.getRemoteableProxy(Statuses.class);
  // etc for the other ~30 endpoints
}

Now any class that has a pointer to a Twitter could do the following synchronously: 

StatusesLookupRequest statusesLookupRequest = new StatusesLookupRequest().withId(new ArrayList(“123”,”456”));
List tweets = twitter.statuses.lookup(statusesLookupRequest);

This seems to me like a killer scheme for mapping and wrapping http apis for JVM that we could apply across most of the data providers in Streams.  

Cheers,  
Steve

P.S. for a future thread, how about asynchronous access?
On March 22, 2017 at 11:17:36 AM, James Bognar (james.bognar@salesforce.com(mailto:james.bognar@salesforce.com)) wrote:

> *This makes a lot of sense to me. If it’s possible to also allow for an
> in-line override of Serializer or Parser, that would limit the number of
> RestClients our provider classes need to create (to 1).*
>  
> Will do.
>  
>  
> *And you can also specify arrays...getResponse(MyBean[].class). This is
> perfect. I remember now seeing the Type,Type… method in the release notes
> and will try it out right away. Of course, I’m hoping that RemoteableProxy
> can be used across the board, if so we won’t need implementation classes
> that would have to do this at all.*
>  
> I need to update the javadocs on the RestClient.getResponse(Type,Type...)
> method. It's not clear from the docs how to use it. For now, just refer
> to the Parser#parse(Type,Type...) for how that works for maps and
> collections.
>  
> If you're interested in the remoteable proxies, you'll probably be
> interested in what I've been working on this week...adding interface
> proxies using @RestMethod. It's a simplified way to define them without
> having to use the RemoteableServlet. Instead, you just define a
> @RestMethod(name="PROXY") method with an interface return type, like so....
>  
> /**
> * [PROXY /*]
> * Return a proxy interface to IAddressBook.
> */
> @RestMethod(name="PROXY", path="/myproxy/*")
> public IAddressBook getProxy() {
> return addressBook;
> }
> On the client side, you get the proxy using RestClient like so....
>  
> IAddressBook ab = client.getRemoteableProxy(IAddressBook.class,
> "/addressBook/myproxy");
> Under-the-covers, a method call is simply a POST with parameters and
> returned object marshalled in the HTTP request and response bodies, and the
> individual methods are addressed using the method signature...e.g....
> POST /addressBook/myproxy/callMyMethod(java.lang.String,boolean)
>  
>  
>  
>  
>  
>  
>  
> On Wed, Mar 22, 2017 at 11:20 AM, sblackmon wrote:
>  
> > Thanks James. Comments below.
> > On March 20, 2017 at 11:48:16 AM, James Bognar (
> > james.bognar@salesforce.com) wrote:
> >
> > Hi Steve!
> >
> > I'm in training today, so my responses may not be prompt.
> >
> > Heads up....in 6.2.0 (what I'm working on now, currently labeled 6.1.1),
> > I'm revamping the RestClient code to use builders just like I did for the
> > serializers and parsers in 6.1.0. So now's a good time for suggested
> > changes! I think the new design makes it considerably easier to understand
> > and reuse HttpClients or HttpClientBuilders.
> >
> > You're correct that a RestClient only uses a single serializer/parser
> > pair. The thoughts were...
> > 1) You avoid having to specify the Accept and Content-Type on the RestCall
> > object.
> > 2) Typical real-world scenario would be that you're only interested in
> > working in a particular language.
> >
> > If you anticipate needing support for multiple languages, it won't be
> > difficult to add. Most likely with a 'default' language, and if you want
> > to use one of the others, you need to do...
> > RestClient.doX().setAccept("text/foo").setContentType("
> > text/foo").getResponse(X);
> >
> > Let me know if you want this.
> > This makes a lot of sense to me. If it’s possible to also allow for an
> > in-line override of Serializer or Parser, that would limit the number of
> > RestClients our provider classes need to create (to 1).
> >
> >
> >
> > *I also am thinking that a new method on RestClient that allowed you to
> > doGet from an request POJO, and have it converted into parameters (using
> > BeanMap?) would help make this easier.*
> > I'm not sure I understand. Can you provide a code example? (or is it in
> > the branch already?)
> > Here’s a specific use case from STREAMS-496.
> >
> > We have an interface that describes the behavior of an external REST
> > endpoint:
> >
> > https://github.com/steveblackmon/incubator-streams/blob/STREAMS-496/
> > streams-contrib/streams-provider-twitter/src/main/java/org/apache/streams/
> > twitter/api/Statuses.java
> >
> > The module contains POJOs for the inputs and outputs of these endpoints,
> > generate from jsonschemas.
> >
> > https://github.com/steveblackmon/incubator-streams/blob/STREAMS-496/
> > streams-contrib/streams-provider-twitter/src/main/
> > jsonschema/org/apache/streams/twitter/api/StatusesLookupRequest.json
> >
> > As I understand, If the third-party endpoints worked on the ‘post with
> > json to get json’ model, then we could use juneau’s RemotableProxy
> > capability to execute these transactions with just the POJOs and the
> > interface, no implementation of the interface required! Very cool...
> > However, the third-party endpoints actually use a ‘get with a bunch of
> > params to get json’ model, and defining the interface methods as a chain of
> > 10+ primitives, most of which are optional, is ugly and difficult to use in
> > java. I’d much prefer to define the interface using a ‘one POJO in, one
> > POJO out’ (like in the links above), and use the fluent builders on those
> > beans to craft the request objects.
> >
> > My suggestion is to add a generic swap capability usable by RestClient or
> > RemoteableProxy that can translate a single (probably flat) POJO argument
> > into get parameters transparently, so that remotableproxy using get
> > requests with complex argument structures can be as easy to code and easy
> > to read as those using post requests with payloads.
> >
> > If this sounds good to you, put it in JIRA and I’ll take a shot at the
> > implementation.
> >
> >
> >
> > *Also wondering whether type erasure will limit the flexibility of
> > restCall.getResponse(T), when the result comes back as a List. In my own
> > APIs I always return an Object but a top-level array is fairly common
> > practice.*
> >
> > The getResponse(Type,Type...) method should allow you to reconstruct
> > parameterized lists and maps.
> > For example:
> > getResponse(LinkedList.class,MyBean.class) - A list of beans.
> > getResponse(HashMap.class,String.class,LinkedList.class,MyBean.class) - A
> > hashmap with string keys and list of beans values.
> >
> > And you can also specify arrays...getResponse(MyBean[].class).
> > This is perfect. I remember now seeing the Type,Type… method in the
> > release notes and will try it out right away. Of course, I’m hoping that
> > RemoteableProxy can be used across the board, if so we won’t need
> > implementation classes that would have to do this at all.
> >
> >
> >
> > Refer to the Parser#parse(Object input, Type type, Type...args) javadocs
> > for info. The RestCall#getResponse() should act the same.
> >
> >
> >
> > On Mon, Mar 20, 2017 at 2:55 AM, sblackmon wrote:
> >
> > > Hello,
> > >
> > > I’m working on a class that uses RestClient to implement several
> > > contextually related methods.
> > >
> > > Each method has a POJO describing the request, and a POJO describing the
> > > response (some methods return a list of the response POJOs).
> > >
> > > As I understand from reading docs for 6.1.1-incubating-SNAPSHOT, while a
> > > RestServlet may bind multiple Serializers and Parsers, a RestClient may
> > > only bind one of each.
> > >
> > > So i guess that means I need to instantiate a different RestClient for
> > > each supported method, or bind a single custom Serializer and Parser
> > that
> > > can handle all of the request and response objects?
> > >
> > > I notice that it’s easy to create and re-use one HttpClient across
> > > RestClients, and there’s presumably no problem reusing all the member
> > > objects of RestClient, so there should be minimal performance overhead
> > to
> > > holding more than one on the class, or even creating a new RestClient
> > for
> > > every call is I don’t close the connection.
> > >
> > > I also am thinking that a new method on RestClient that allowed you to
> > > doGet from an request POJO, and have it converted into parameters (using
> > > BeanMap?) would help make this easier.
> > >
> > > Also wondering whether type erasure will limit the flexibility of
> > > restCall.getResponse(T), when the result comes back as a List. In my own
> > > APIs I always return an Object but a top-level array is fairly common
> > > practice.
> > >
> > > Anyway, I’ve pushed some early work to this branch, and I’d be
> > interested
> > > in feedback as I work through this, whether it’s on the right track to
> > > minimize code complexity and maximize performance for what we’re trying
> > to
> > > do.
> > >
> > > I’m not yet to the point of running any integration tests using this new
> > > implementation but hope to be soon.
> > >
> > > https://github.com/apache/incubator-streams/compare/
> > > master...steveblackmon:STREAMS-496
> > >
> > > Thanks in advance,
> > > Steve (Streams)
> >
> >
> >
> >
> > --
> > James Bognar
> >
>  
>  
>  
> --
> James Bognar


Re: Advice regarding Juneau RestClient, RestCall, Serializers, best practices

Posted by James Bognar <ja...@salesforce.com>.
*This makes a lot of sense to me.  If it’s possible to also allow for an
in-line override of Serializer or Parser, that would limit the number of
RestClients our provider classes need to create (to 1).*

Will do.


*And you can also specify arrays...getResponse(MyBean[].class). This is
perfect.  I remember now seeing the Type,Type… method in the release notes
and will try it out right away.  Of course, I’m hoping that RemoteableProxy
can be used across the board, if so we won’t need implementation classes
that would have to do this at all.*

I need to update the javadocs on the RestClient.getResponse(Type,Type...)
method.  It's not clear from the docs how to use it.  For now, just refer
to the Parser#parse(Type,Type...) for how that works for maps and
collections.

If you're interested in the remoteable proxies, you'll probably be
interested in what I've been working on this week...adding interface
proxies using @RestMethod.  It's a simplified way to define them without
having to use the RemoteableServlet.  Instead, you just define a
@RestMethod(name="PROXY") method with an interface return type, like so....

/**
* [PROXY /*]
* Return a proxy interface to IAddressBook.
*/
@RestMethod(name="PROXY", path="/myproxy/*")
public IAddressBook getProxy() {
   return addressBook;
}
On the client side, you get the proxy using RestClient like so....

IAddressBook ab = client.getRemoteableProxy(IAddressBook.class,
"/addressBook/myproxy");
Under-the-covers, a method call is simply a POST with parameters and
returned object marshalled in the HTTP request and response bodies, and the
individual methods are addressed using the method signature...e.g....
POST /addressBook/myproxy/callMyMethod(java.lang.String,boolean)







On Wed, Mar 22, 2017 at 11:20 AM, sblackmon <sb...@apache.org> wrote:

> Thanks James.  Comments below.
> On March 20, 2017 at 11:48:16 AM, James Bognar (
> james.bognar@salesforce.com) wrote:
>
> Hi Steve!
>
> I'm in training today, so my responses may not be prompt.
>
> Heads up....in 6.2.0 (what I'm working on now, currently labeled 6.1.1),
> I'm revamping the RestClient code to use builders just like I did for the
> serializers and parsers in 6.1.0. So now's a good time for suggested
> changes! I think the new design makes it considerably easier to understand
> and reuse HttpClients or HttpClientBuilders.
>
> You're correct that a RestClient only uses a single serializer/parser
> pair. The thoughts were...
> 1) You avoid having to specify the Accept and Content-Type on the RestCall
> object.
> 2) Typical real-world scenario would be that you're only interested in
> working in a particular language.
>
> If you anticipate needing support for multiple languages, it won't be
> difficult to add. Most likely with a 'default' language, and if you want
> to use one of the others, you need to do...
> RestClient.doX().setAccept("text/foo").setContentType("
> text/foo").getResponse(X);
>
> Let me know if you want this.
> This makes a lot of sense to me.  If it’s possible to also allow for an
> in-line override of Serializer or Parser, that would limit the number of
> RestClients our provider classes need to create (to 1).
>
>
>
> *I also am thinking that a new method on RestClient that allowed you to
> doGet from an request POJO, and have it converted into parameters (using
> BeanMap?) would help make this easier.*
> I'm not sure I understand. Can you provide a code example? (or is it in
> the branch already?)
> Here’s a specific use case from STREAMS-496.
>
> We have an interface that describes the behavior of an external REST
> endpoint:
>
> https://github.com/steveblackmon/incubator-streams/blob/STREAMS-496/
> streams-contrib/streams-provider-twitter/src/main/java/org/apache/streams/
> twitter/api/Statuses.java
>
> The module contains POJOs for the inputs and outputs of these endpoints,
> generate from jsonschemas.
>
> https://github.com/steveblackmon/incubator-streams/blob/STREAMS-496/
> streams-contrib/streams-provider-twitter/src/main/
> jsonschema/org/apache/streams/twitter/api/StatusesLookupRequest.json
>
> As I understand, If the third-party endpoints worked on the ‘post with
> json to get json’ model, then we could use juneau’s RemotableProxy
> capability to execute these transactions with just the POJOs and the
> interface, no implementation of the interface required!  Very cool...
> However, the third-party endpoints actually use a ‘get with a bunch of
> params to get json’ model, and defining the interface methods as a chain of
> 10+ primitives, most of which are optional, is ugly and difficult to use in
> java.  I’d much prefer to define the interface using a ‘one POJO in, one
> POJO out’ (like in the links above), and use the fluent builders on those
> beans to craft the request objects.
>
> My suggestion is to add a generic swap capability usable by RestClient or
> RemoteableProxy that can translate a single (probably flat) POJO argument
> into get parameters transparently, so that remotableproxy using get
> requests with complex argument structures can be as easy to code and easy
> to read as those using post requests with payloads.
>
> If this sounds good to you, put it in JIRA and I’ll take a shot at the
> implementation.
>
>
>
> *Also wondering whether type erasure will limit the flexibility of
> restCall.getResponse(T), when the result comes back as a List. In my own
> APIs I always return an Object but a top-level array is fairly common
> practice.*
>
> The getResponse(Type,Type...) method should allow you to reconstruct
> parameterized lists and maps.
> For example:
> getResponse(LinkedList.class,MyBean.class) - A list of beans.
> getResponse(HashMap.class,String.class,LinkedList.class,MyBean.class) - A
> hashmap with string keys and list of beans values.
>
> And you can also specify arrays...getResponse(MyBean[].class).
> This is perfect.  I remember now seeing the Type,Type… method in the
> release notes and will try it out right away.  Of course, I’m hoping that
> RemoteableProxy can be used across the board, if so we won’t need
> implementation classes that would have to do this at all.
>
>
>
> Refer to the Parser#parse(Object input, Type type, Type...args) javadocs
> for info. The RestCall#getResponse() should act the same.
>
>
>
> On Mon, Mar 20, 2017 at 2:55 AM, sblackmon <sb...@apache.org> wrote:
>
> > Hello,
> >
> > I’m working on a class that uses RestClient to implement several
> > contextually related methods.
> >
> > Each method has a POJO describing the request, and a POJO describing the
> > response (some methods return a list of the response POJOs).
> >
> > As I understand from reading docs for 6.1.1-incubating-SNAPSHOT, while a
> > RestServlet may bind multiple Serializers and Parsers, a RestClient may
> > only bind one of each.
> >
> > So i guess that means I need to instantiate a different RestClient for
> > each supported method, or bind a single custom Serializer and Parser
> that
> > can handle all of the request and response objects?
> >
> > I notice that it’s easy to create and re-use one HttpClient across
> > RestClients, and there’s presumably no problem reusing all the member
> > objects of RestClient, so there should be minimal performance overhead
> to
> > holding more than one on the class, or even creating a new RestClient
> for
> > every call is I don’t close the connection.
> >
> > I also am thinking that a new method on RestClient that allowed you to
> > doGet from an request POJO, and have it converted into parameters (using
> > BeanMap?) would help make this easier.
> >
> > Also wondering whether type erasure will limit the flexibility of
> > restCall.getResponse(T), when the result comes back as a List. In my own
> > APIs I always return an Object but a top-level array is fairly common
> > practice.
> >
> > Anyway, I’ve pushed some early work to this branch, and I’d be
> interested
> > in feedback as I work through this, whether it’s on the right track to
> > minimize code complexity and maximize performance for what we’re trying
> to
> > do.
> >
> > I’m not yet to the point of running any integration tests using this new
> > implementation but hope to be soon.
> >
> > https://github.com/apache/incubator-streams/compare/
> > master...steveblackmon:STREAMS-496
> >
> > Thanks in advance,
> > Steve (Streams)
>
>
>
>
> --
> James Bognar
>



-- 
James Bognar

Re: Advice regarding Juneau RestClient, RestCall, Serializers, best practices

Posted by sblackmon <sb...@apache.org>.
Thanks James.  Comments below.
On March 20, 2017 at 11:48:16 AM, James Bognar (james.bognar@salesforce.com) wrote:

Hi Steve! 

I'm in training today, so my responses may not be prompt. 

Heads up....in 6.2.0 (what I'm working on now, currently labeled 6.1.1), 
I'm revamping the RestClient code to use builders just like I did for the 
serializers and parsers in 6.1.0. So now's a good time for suggested 
changes! I think the new design makes it considerably easier to understand 
and reuse HttpClients or HttpClientBuilders. 

You're correct that a RestClient only uses a single serializer/parser 
pair. The thoughts were... 
1) You avoid having to specify the Accept and Content-Type on the RestCall 
object. 
2) Typical real-world scenario would be that you're only interested in 
working in a particular language. 

If you anticipate needing support for multiple languages, it won't be 
difficult to add. Most likely with a 'default' language, and if you want 
to use one of the others, you need to do... 
RestClient.doX().setAccept("text/foo").setContentType("text/foo").getResponse(X); 

Let me know if you want this. 
This makes a lot of sense to me.  If it’s possible to also allow for an in-line override of Serializer or Parser, that would limit the number of RestClients our provider classes need to create (to 1).



*I also am thinking that a new method on RestClient that allowed you to 
doGet from an request POJO, and have it converted into parameters (using 
BeanMap?) would help make this easier.* 
I'm not sure I understand. Can you provide a code example? (or is it in 
the branch already?) 
Here’s a specific use case from STREAMS-496.

We have an interface that describes the behavior of an external REST endpoint:

https://github.com/steveblackmon/incubator-streams/blob/STREAMS-496/streams-contrib/streams-provider-twitter/src/main/java/org/apache/streams/twitter/api/Statuses.java 

The module contains POJOs for the inputs and outputs of these endpoints, generate from jsonschemas.

https://github.com/steveblackmon/incubator-streams/blob/STREAMS-496/streams-contrib/streams-provider-twitter/src/main/jsonschema/org/apache/streams/twitter/api/StatusesLookupRequest.json

As I understand, If the third-party endpoints worked on the ‘post with json to get json’ model, then we could use juneau’s RemotableProxy capability to execute these transactions with just the POJOs and the interface, no implementation of the interface required!  Very cool...
However, the third-party endpoints actually use a ‘get with a bunch of params to get json’ model, and defining the interface methods as a chain of 10+ primitives, most of which are optional, is ugly and difficult to use in java.  I’d much prefer to define the interface using a ‘one POJO in, one POJO out’ (like in the links above), and use the fluent builders on those beans to craft the request objects.

My suggestion is to add a generic swap capability usable by RestClient or RemoteableProxy that can translate a single (probably flat) POJO argument into get parameters transparently, so that remotableproxy using get requests with complex argument structures can be as easy to code and easy to read as those using post requests with payloads.

If this sounds good to you, put it in JIRA and I’ll take a shot at the implementation.



*Also wondering whether type erasure will limit the flexibility of 
restCall.getResponse(T), when the result comes back as a List. In my own 
APIs I always return an Object but a top-level array is fairly common 
practice.* 

The getResponse(Type,Type...) method should allow you to reconstruct 
parameterized lists and maps. 
For example: 
getResponse(LinkedList.class,MyBean.class) - A list of beans. 
getResponse(HashMap.class,String.class,LinkedList.class,MyBean.class) - A 
hashmap with string keys and list of beans values. 

And you can also specify arrays...getResponse(MyBean[].class). 
This is perfect.  I remember now seeing the Type,Type… method in the release notes and will try it out right away.  Of course, I’m hoping that RemoteableProxy can be used across the board, if so we won’t need implementation classes that would have to do this at all.



Refer to the Parser#parse(Object input, Type type, Type...args) javadocs 
for info. The RestCall#getResponse() should act the same. 



On Mon, Mar 20, 2017 at 2:55 AM, sblackmon <sb...@apache.org> wrote: 

> Hello, 
> 
> I’m working on a class that uses RestClient to implement several 
> contextually related methods. 
> 
> Each method has a POJO describing the request, and a POJO describing the 
> response (some methods return a list of the response POJOs). 
> 
> As I understand from reading docs for 6.1.1-incubating-SNAPSHOT, while a 
> RestServlet may bind multiple Serializers and Parsers, a RestClient may 
> only bind one of each. 
> 
> So i guess that means I need to instantiate a different RestClient for 
> each supported method, or bind a single custom Serializer and Parser that 
> can handle all of the request and response objects? 
> 
> I notice that it’s easy to create and re-use one HttpClient across 
> RestClients, and there’s presumably no problem reusing all the member 
> objects of RestClient, so there should be minimal performance overhead to 
> holding more than one on the class, or even creating a new RestClient for 
> every call is I don’t close the connection. 
> 
> I also am thinking that a new method on RestClient that allowed you to 
> doGet from an request POJO, and have it converted into parameters (using 
> BeanMap?) would help make this easier. 
> 
> Also wondering whether type erasure will limit the flexibility of 
> restCall.getResponse(T), when the result comes back as a List. In my own 
> APIs I always return an Object but a top-level array is fairly common 
> practice. 
> 
> Anyway, I’ve pushed some early work to this branch, and I’d be interested 
> in feedback as I work through this, whether it’s on the right track to 
> minimize code complexity and maximize performance for what we’re trying to 
> do. 
> 
> I’m not yet to the point of running any integration tests using this new 
> implementation but hope to be soon. 
> 
> https://github.com/apache/incubator-streams/compare/ 
> master...steveblackmon:STREAMS-496 
> 
> Thanks in advance, 
> Steve (Streams) 




-- 
James Bognar 

Re: Advice regarding Juneau RestClient, RestCall, Serializers, best practices

Posted by James Bognar <ja...@salesforce.com>.
Hi Steve!

I'm in training today, so my responses may not be prompt.

Heads up....in 6.2.0 (what I'm working on now, currently labeled 6.1.1),
I'm revamping the RestClient code to use builders just like I did for the
serializers and parsers in 6.1.0.  So now's a good time for suggested
changes!  I think the new design makes it considerably easier to understand
and reuse HttpClients or HttpClientBuilders.

You're correct that a RestClient only uses a single serializer/parser
pair.  The thoughts were...
1) You avoid having to specify the Accept and Content-Type on the RestCall
object.
2) Typical real-world scenario would be that you're only interested in
working in a particular language.

If you anticipate needing support for multiple languages, it won't be
difficult to add.  Most likely with a 'default' language, and if you want
to use one of the others, you need to do...
RestClient.doX().setAccept("text/foo").setContentType("text/foo").getResponse(X);

Let me know if you want this.

*I also am thinking that a new method on RestClient that allowed you to
doGet from an request POJO, and have it converted into parameters (using
BeanMap?) would help make this easier.*
I'm not sure I understand.  Can you provide a code example?  (or is it in
the branch already?)

*Also wondering whether type erasure will limit the flexibility of
restCall.getResponse(T), when the result comes back as a List.  In my own
APIs I always return an Object but a top-level array is fairly common
practice.*

The getResponse(Type,Type...) method should allow you to reconstruct
parameterized lists and maps.
For example:
getResponse(LinkedList.class,MyBean.class) - A list of beans.
getResponse(HashMap.class,String.class,LinkedList.class,MyBean.class) - A
hashmap with string keys and list of beans values.

And you can also specify arrays...getResponse(MyBean[].class).

Refer to the Parser#parse(Object input, Type type, Type...args) javadocs
for info.  The RestCall#getResponse() should act the same.



On Mon, Mar 20, 2017 at 2:55 AM, sblackmon <sb...@apache.org> wrote:

> Hello,
>
> I’m working on a class that uses RestClient to implement several
> contextually related methods.
>
> Each method has a POJO describing the request, and a POJO describing the
> response (some methods return a list of the response POJOs).
>
> As I understand from reading docs for 6.1.1-incubating-SNAPSHOT, while a
> RestServlet may bind multiple Serializers and Parsers, a RestClient may
> only bind one of each.
>
> So i guess that means I need to instantiate a different RestClient for
> each supported method, or bind a single custom Serializer and Parser that
> can handle all of the request and response objects?
>
> I notice that it’s easy to create and re-use one HttpClient across
> RestClients, and there’s presumably no problem reusing all the member
> objects of RestClient, so there should be minimal performance overhead to
> holding more than one on the class, or even creating a new RestClient for
> every call is I don’t close the connection.
>
> I also am thinking that a new method on RestClient that allowed you to
> doGet from an request POJO, and have it converted into parameters (using
> BeanMap?) would help make this easier.
>
> Also wondering whether type erasure will limit the flexibility of
> restCall.getResponse(T), when the result comes back as a List.  In my own
> APIs I always return an Object but a top-level array is fairly common
> practice.
>
> Anyway, I’ve pushed some early work to this branch, and I’d be interested
> in feedback as I work through this, whether it’s on the right track to
> minimize code complexity and maximize performance for what we’re trying to
> do.
>
> I’m not yet to the point of running any integration tests using this new
> implementation but hope to be soon.
>
> https://github.com/apache/incubator-streams/compare/
> master...steveblackmon:STREAMS-496
>
> Thanks in advance,
> Steve (Streams)




-- 
James Bognar