Promising. As I am just starting to architect a new app that needs a strong formal ReST interface, I am particularly interested in this.
Question; In your example you have a query link without arguments. How are those supposed to be provided? (Gosh I need to read up on this again...) Cheers Niclas On Thu, Oct 13, 2011 at 12:13 PM, Rickard Öberg <[email protected]> wrote: > Hi, > > (WARNING: Longish email on how to do REST properly) > > Based on my experience with REST API design in Streamflow, I want to > investigate a redesign of how we do REST client and server libraries, > specifically in order to enable Level 3 REST API's, meaning full support for > hypermedia to drive state transitions in an application. > > The server part has already been reasonably explored in Streamflow, and the > result is that use cases should be exposed, rather than the traditional > domain objects. This makes it possible to make the client very very thin, > and all business rules remain on the server where they belong. The current > REST library code in Git relies on DCI being used, but I intend to factor > this out so that you can choose to do the traditional "service+anemic > domain" if you want to. The main point is to support exposing REST resources > that focus on use cases and hypermedia, whether or not DCI is used. > > On the client, I have been thinking a lot about what Roy wrote in his > thesis, which boils down to "client makes GET request, based on relation of > link invoked and response (headers+hypermedia) make a decision, and then > follow links or invoke forms to perform state transitions". It's a state > machine. This is different from your average REST client today in that this > model explicitly says that you need to do a GET first (otherwise you have > nothing to react to), that the "rel" of the link you followed is important > (otherwise context is unknown), and that the client should not make > assumptions about what comes back (otherwise you cannot deal with > exceptions, on system and application level). > > The current REST client approach which is imperative: > result = client.get(somelink) > does not allow for any of the above. Instead, the client code should first > register handlers for what to do in various circumstances, and then simply > perform one operation: "refresh". This will trigger the first GET to the > bookmarked URL, and after that the handlers will do all the work, based on > the result. A handler may continue the work by invoking new requests, or it > may abort. "refresh" does not return any value, and usually does not throw > any exceptions. > > Example: > crc.onResource( new ResultHandler<Resource>() > { > @Override > public void handleResult( Resource result, ContextResourceClient client ) > { > // This may throw IAE if no link with relation > // "querywithoutvalue" is found in the Resource > client.query( "querywithoutvalue", null ); > } > } ). > onQuery( "querywithoutvalue", TestResult.class, new > ResultHandler<TestResult>() > { > @Override > public void handleResult( TestResult result, ContextResourceClient client > ) > { > Assert.assertThat( result.xyz().get(), CoreMatchers.equalTo( "bar" ) > ); > } > } ); > > crc.refresh(); > --- > The client first builds up the set of handlers, and describe what they > should react to. The client then invokes "refresh" which will trigger the > first GET on the bookmark URL. This will return a representation of that > context as a Resource, and the handler for that is invoked. This then > invokes the link with relation "querywithoutvalue" with no input (no request > parameters needed). The result of that is then handled by another handler, > and the invocation of "refresh" then returns successfully. Note that the > first handler may not directly handle the "result" of > client.query("querywithoutvalue, null) as it cannot be assumed what happens > next. All you know is that you are following a link. > > On crc (ContextResourceClient) it is also possible to registers handlers > that are always applied, such as error handlers. Here is the setup of crc: > // Create Restlet client and bookmark Reference > Client client = new Client( Protocol.HTTP ); > Reference ref = new Reference( "http://localhost:8888/" ); > ContextResourceClientFactory contextResourceClientFactory = > module.newObject( ContextResourceClientFactory.class, client, new > NullResponseHandler() ); > contextResourceClientFactory.setAcceptedMediaTypes( > MediaType.APPLICATION_JSON ); > > // Handle logins > contextResourceClientFactory.setErrorHandler( new ErrorHandler().onError( > ErrorHandler.AUTHENTICATION_REQUIRED, new ResponseHandler() > { > // Only try to login once > boolean tried = false; > > @Override > public void handleResponse( Response response, ContextResourceClient > client ) > { > // If we have already tried to login, fail! > if (tried) > throw new ResourceException( response.getStatus() ); > > tried = true; > client.getContextResourceClientFactory().getInfo().setUser( new > User("rickard", "secret") ); > > // Try again > client.refresh(); > } > } ).onError( ErrorHandler.RECOVERABLE_ERROR, new ResponseHandler() > { > @Override > public void handleResponse( Response response, ContextResourceClient > client ) > { > // Try to restart this scenario > client.refresh(); > } > } ) ); > > crc = contextResourceClientFactory.newClient( ref ); > --- > These general handlers cover what to do for login and error handling, for > example. In the traditional REST client this is not as easy to do, as you > are more or less assuming a "happy path" all the time. In the above scenario > there could be any number of steps between doing "refresh" and getting to > the meat of the use case, such as doing a signup for the website, login, > redirects to other servers, error handling and retries, etc. It becomes > possible to blend general application and error handling logic with use case > specific handlers. > > That's basically it. This is where I want to go with support for REST, as a > way to truly leverage the REST ideas and make it very easy to do REST > applications *and* clients based on Qi4j, by keeping the application logic > on the server. In the long run there would also be a JavaScript version of > the client, with the same characteristics, so that you can easily build a > jQuery UI for Qi4j REST apps. > > Thoughts on that? > > /Rickard > > _______________________________________________ > qi4j-dev mailing list > [email protected] > http://lists.ops4j.org/mailman/listinfo/qi4j-dev > -- Niclas Hedhman, Software Developer http://www.qi4j.org - New Energy for Java I live here; http://tinyurl.com/3xugrbk I work here; http://tinyurl.com/6a2pl4j I relax here; http://tinyurl.com/2cgsug _______________________________________________ qi4j-dev mailing list [email protected] http://lists.ops4j.org/mailman/listinfo/qi4j-dev

