click-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Malcolm Edgar <malcolm.ed...@gmail.com>
Subject Re: Click Services
Date Mon, 20 May 2013 11:07:07 GMT
Hi Bob,

thanks for the links to Roy's blog post. I have to admit I have used the
REST terminology a lot when talking about JSON RPC, so I am trying to be
more precise nowdays.

The WADL looks interesting, however writing an XML descriptor to generate
doco would not be fun.

Using straight reflection wouldn't probably work because the Java
reflection API doesn't tell you what the parameter names are.  We would
need to add annotations to make this work.  However writing code with
annotations for doco is pretty yucky, e.g.

package com.mycorp.services;

@Doc(desc="Providers Customer Account query services")
public class CustomerService {

@Doc(desc="Return the list of customers matching the given keyword and
active status")
public List<Customer> getCustomers(
@Doc(param="keyword", desc="Search for customers matching the keyword
(optional") String keyword,
@Doc(param="active", desc="Include only active accounts (optional)")
boolean active) {
 ..
}
}

Still it would be a pretty nice feature to have APIs which are self
describing.

Its interesting using the returned POJO to create the documentation. Maybe
a valid approach, especially if we can rely on a decent library to do the
marshalling.  Using a reflection based approach would give us the most
flexibility, so you could return an ActionResult or a POJO and the Filter
would handle this result.

Do you think there is merit in having stateful/singleton services ?

In terms of mapping, I think we could develop some reasonable conventions
like we have done with Click pages and cache the results, e.g.

GET
/mycorp/services/customer-service/get-customers/?keyword=john&active=true

Would attempt to look up the class paths:

com.mycorp.services.CustomerService

Then attempt to resolve the method:

getCustomers(String, String)

While this is is favoring convention over configuration, in my experience
this works really well in building large systems.

Would be good for the Filter to use the Click Logging service, and log the
appropriate output depending upon the application mode.

It would also would be nice to have the Filter support formatting the JSON
response to make it more human readable, with an optional formatJson=true
request parameter.

While all these things may appear to be pretty minor benefits, I think they
would have a cumulative productivity benefit which would be significant.

regards Malcolm










On Mon, May 20, 2013 at 7:14 PM, Bob Schellink <sabob1@gmail.com> wrote:

> Hi Malcolm,
>
> Multiple requests per service is what I have in mind. JSON over HTTP
> instead of REST.
>
> Interestingly, Roy Fielding says a service isn't REST if it isn't
> hypertext driven:
> http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
>
> Basically nobody is doing REST anyway ;-)
>
> Wrt self documenting efforts, there is Swagger and WADL:
> developers.helloreverb.com/swagger/
>
> Swager Demo:
> http://petstore.swagger.wordnik.com/
>
> WADL:
> http://en.wikipedia.org/wiki/Web_Application_Description_Language
>
> I'm not sure how we could self describe these services though. Perhaps a
> url like '/services' could generate an HTML page with links to all
> registered services. But Click will then have to "discover" it's own
> services somehow via reflection or annotations or at build time.
>
> We also have to provide the input and outputs (JSON) of the services. If a
> service looked like this:
>
> public Person getPerson(String id) {
> }
>
> we could generate the JSON of a Person instance, as long as it has a
> no-args constructor. The JSON won't have any values though so it would look
> like:
>
> {Person: {'firstname': null, 'surname': null, 'dateOfBirth': null}}
>
> unless we add default values for primitives:
> {Person: {'firstname': "example", 'surname': "example", 'dateOfBirth':
> "2013/01/01" }}
>
> If we target JDK7 we could use the new InvokeDynamic instead of
> reflection. InvokeDynamic should be quite a bit faster.
>
> Another note from your example:
> customerservice/getcustomer/?id=123456
>
> how would one dynamically map customerservice to CustomerService? The URL
> would have to respect the class case otherwise we won't be able to look it
> up automatically. Unless there is a mapping somewhere (web.xml or
> annotation) which maps the lower case customerservice to CustomerService.
>
> Kind regards
>
> Bob
>
>
> On Mon, May 20, 2013 at 5:49 AM, Malcolm Edgar <malcolm.edgar@gmail.com>wrote:
>
>> I think there is some merit in this stuff for RPC JSON services.
>>
>> I would like to see some form of API documenting feature, this is a
>> problem with existing services they are hard to program to because they are
>> not self describing like Web Services are. This could be tricky to
>> implement however, and you may want to disable this on production systems.
>>
>> Interesting to think what the design should be:
>>
>> 1) single RPC method per class, with the service implementing some
>> service interface, e.g.
>>
>>    com.mycorp.service.GetCustomerService
>>
>>    /mycorp/service/getcustomer/?id=123456
>>
>>
>> 2) multiple RPC methods per class, using reflection to lookup the methods:
>>
>>    com.mycorp.service.CustomerService
>>
>>    /mycorp/service/customerservice/getcustomer/?id=123456
>>
>>    /mycorp/service/customerservice/getcustomerlist/?keyword=bob
>>
>>
>> In terms of whether we should support singleton /prototype (Spring
>> terminology) services. I distrust stateful services and would prefer new
>> service instances to be created per request. If people what to cache stuff,
>> they can do this themselves in the servlet context.  If we take this
>> approach I don't think we need lifecycle methods onInit(), onDestroy() etc.
>>  This would also keep it simple, we dont need configuration or annoations
>> to describe the service lifecycle.
>>
>> In terms of mapping requests to service, I think Bob's on demand approach
>> would be good where by we cache resolved look-ups. For implementation agree
>> the Filter would be the best approach as this would avoid impacting the
>> ClickServlet and the XML configuration stuff.  It would be good do have
>> some package automapping stuff like we do with Click pages. Maybe this
>> could be configure against the filter in the web.xml
>>
>> regards
>>
>>
>> On Wed, May 15, 2013 at 5:43 AM, Bob Schellink <sabob1@gmail.com> wrote:
>>
>>> On 2013/05/14 15:45, Malcolm Edgar wrote:
>>>
>>>> I think this is an interesting discussion.  I am seeing existing
>>>> Multiple Page Applications (MPA),
>>>> which is Clicks forte, evolve into hybrid MPA / Single Page
>>>> Applications (SPA) using frameworks like
>>>> AngularJS.
>>>>
>>>> For serving JSON/RPC we have been using both hand coded Servlets with
>>>> net.sf.json.JSONSerializer and
>>>> using services built with RESTEasy (http://www.jboss.org/resteasy**).
>>>>  The RESTEasy approach is
>>>> more idiomatic Java (lots of layers of abstraction) and works well 99%
>>>> of time.
>>>>
>>>> I am not sure what the value Click could provide for services.
>>>>
>>>
>>> Nods, we will be reinventing the wheel a bit.
>>>
>>>
>>>  While I agree Velocity templates
>>>
>>>> would be useful for rendering a JSON response, the main problem in this
>>>> space is marshalling JSON
>>>> request data into Java objects. Maybe Marco google library would be
>>>> good for this.
>>>>
>>>
>>> I'm currently using GSON[1], mostly because their docs is
>>> straightforward.
>>>
>>>
>>>
>>>
>>>> How would you see the services being registered, e.g. XML definition or
>>>> auto-mapped some how ?
>>>>
>>>
>>> Guess annotation based but it looks like a pain to discover the
>>> annotated classes. There are some libs to help with that part but EE
>>> environments are tricky eg. JBoss 7 has a custom file system implementation
>>> which is tricky to 'scan'. Preprocessor could also be used at compile time
>>> to discover annotated classes and build an index of classes.
>>>
>>> One could also use plain interfaces and build up a cache at runtime eg:
>>> each request that matches a valid class is placed in a map and cached for
>>> faster retrieval in the future.
>>>
>>> Kind regards
>>>
>>> Bob
>>>
>>> [1]: http://code.google.com/p/**google-gson/<http://code.google.com/p/google-gson/>
>>>
>>
>>
>

Mime
View raw message