Check out Restfulie’s website if you still did not.
CRUD through HTTP is a good step forward to using resources and becoming RESTful, another step further into it is to make use of hypermedia based services and this gem allows you to do it really fast.
You can read the article on using the web for real which gives an introduction to hypermedia/aware resources.
1. Easy —> writing hypermedia aware resource based clients
2. Easy —> hypermedia aware resource based services
3. Small → it’s not a bloated solution with a huge list of APIs
4. HATEOAS —> clients you are unaware of will not bother if you change your URIs
5. HATEOAS —> services that you consume will not affect your software whenever they change part of their flow or URIs
Restfulie was the first API trying to somehow implement Jim Webber point of view on how RESTFul systems use hypermedia as the way to lead your client’s path through a business process.
You can see a 3rd party comparison between all REST frameworks.
Therefore Restfulie is unique in its feature set when compared to other (JAX-RS) based implementations: looking for simple code and favoring conventions over manual configurations when creating hypermedia aware system. Restfulie also handle content negotiation and its client implements cache and other set of features unsupported so far in other frameworks.
According to Richardson Maturity Model , systems are only to be called RESTFul if they support this kind of state flow transition through hypermedia content contained within resources representations:
<order> <product>basic rails course</product> <product>RESTful training</product> <atom:link rel="payment" href="http://www.caelum.com.br/orders/1/pay" xmlns:atom="http://www.w3.org/2005/Atom"/> <atom:link rel="cancel" href="http://www.caelum.com.br/orders/1" xmlns:atom="http://www.w3.org/2005/Atom"/> </order>
If you are to implement a 3rd level (restful) service, Restfulie is the way to go.
There is a Restfulie guide being built but still in beta version.
You can also download a sample application , both client and server code.
FInally, do not forget to ask your questions at our mailing list .
Restfulie comes many different flavors, java and ruby.
The client side code allows you to hide http-protocol specifics if required, while allowing you to re-configure it when needed.
Example on accessing a resource and its services through the restfulie API:
Order order = new Order(); // place the order order = service("http://www.caelum.com.br/order").post(order); // cancels it resource(order).getRelation("cancel").execute();
This is a simple example how to make your state changes available to your resource consumers:
public class Order implements HypermediaResource { public List<Relation> getRelations(Restfulie control) { if (status.equals("unpaid")) { control.relation("latest").uses(OrderingController.class).get(this); control.relation("cancel").uses(OrderingController.class).cancel(this); } return control.getRelations(); } }
Start downloading all data : the client jars, vraptor jars and both server side and client side application.
You can download a sample client and server side application on the same link, those will be helpful for you too understand how to use Restfulie.
In order to use Restfulie in your client side app, simply add all required jars to your classpath.
Download vraptor’s blank project and configure your web.xml file. You are ready to go.
The entry point for Restfulie’s api is the Restfulie class. It’s basic usage is through the resource method which, given an URI, will allow
you to retrieve a resource or post to a resource controller:
Order order = Restfulie.resource("http://www.caelum.com.br/orders/1").get(); Client client = new Client(); Restfulie.resource("http://www.caelum.com.br/clients").post(client);
Due to the nature of the entry point and the java bytecode, Restfulie is still unable to allow the user to make the http verb even more transparent.
As seen earlier, as soon as you have acquired an object through the use of the restfulie api, you can invoke its transitions:
Order order = Restfulie.resource("http://www.caelum.com.br/orders/1").get(); resource(order).getRelation("cancel").access();
The resource method can be statically imported from the Restfulie class.
Restfulie uses XStream behind the scenes, therefore all XStream related annotations are supported by default when using it.
The following example shows how to alias a type:
@XStreamAlias("order") public class Order { }
More info on how to configure XStream through the use of annotations can be “found in its website”:“http://xstream.codehaus.org”.
By default, Restfulie serializes all primitive, String and enum types. In order to serialize child elements, one has pre-configure Restfulie. This is
the typical usage-pattern applications will face while using restfulie:
Resources resources = Restfulie.resources(); resources.configure(Order.class).include("items"); // the configuration step is completed, so lets use it now: resources.entryAt("http://www.caelum.com.br/clients").post(new Client());
The entire serialization process can be configured either through the Resources interface’s methods or using *XStream*’s explicit configuration.
Most REST frameworks will not help the developer providing etags, last modified and other cache related headers.
Meanwhile, in the server side, Restfulie might add extra headers to handle last modified, etag and max age situations that will improve response time and avoid useless bandwidth consumption. In order to benefit from such cache characteristics, simply implement the RestfulEntity interface.
One can access all possible transitions for an object by invoking a resource’s getRelations method:
List<Relation> relations = resource(order).getRelations();
While typical level 2 frameworks will only provide a statically, compilation time checked, relation/transition invocation, Restfulie allows clients/bots to adapt to REST results, giving your clients even less coupling to your services protocol.
By default, restfulie uses a well known table of defaults for http verb detection according to the rel element:
- destroy, cancel and delete send a DELETE request
- update sends a PUT request
- refresh, reload, show, latest sends a GET request
- other methods sends a POST request
If you want to use a custom http verb in order to send your request, you can do it:
payment = resource(order).getRelation("payment").method(HttpMethod.PUT).accessAndRetrieve(payment);
If you need to send some information to the server, this can be done by passing an argument to the execute method, which will be serialized and sent as the request body’s content:
payment = resource(order).getRelation("payment").method(HttpMethod.PUT).accessAndRetrieve(payment);
Once you have found the entry point you want to use (retrieving a resource or creating one), the javadoc api is a resourcefull place for more info.
The default way to use Restfulie is to define the getRelations method in your resource. The method receives a Restfulie instance (server side version) which allows you to dsl-like create transitions. In order to do that, given a Restfulie object, invoke the transition method with your rel name and the relative controller action:
public List<Relation> getRelations(Restfulie control) { control.relation("delete").uses(OrderingController.class).cancel(this); return control.getRelations(); }
Note that both the OrderingController class with its cancel method are web methods made available through the use of vraptor:
@Resource public OrderingController { @Delete @Path("/order/{order.id}") @Transition public void cancel(Order order) { order = database.getOrder(order.getId()); order.cancel(); status.ok(); } }
Now you need to set up your application package in web.xml. This is the only configuration required:
<context-param> <param-name>br.com.caelum.vraptor.packages</param-name> <param-value>br.com.caelum.vraptor.restfulie,com.your.app.package.without.leading.whitespace</param-value> </context-param>
By using the @Transition to annotate your method, Restfulie will automatically load the order from the database and check for either 404 (object not found), 405 (method not allowed), 409 (conflict: transition is not allowed for this resource’s state) and 406 (content negotiation failed).
This is one of the advantages of using Restfulie over other level 2 Rest frameworks. By supporting hypermedia content and handling transitions out of the box, Restfulie creates a new layer capable
of helping the server to deal with unexpected states.
1. Create your model (i.e. Order)
@XStreamAlias("order") public class Order { private String id; private Location location; private List<Item> items; private transient String status; private Payment payment; public enum Location { takeAway, drinkIn }; // ... } @XStreamAlias("item") public class Item { enum Coffee {LATTE, CAPPUCINO, ESPRESSO}; enum Milk {SKIM, SEMI, WHOLE}; enum Size {SMALL, MEDIUM, LARGE}; private Coffee drink; private int quantity; private Milk milk; private Size size; // ... }
2. Usually the getRelations method would check the resource state in order to coordinate which transitions can be executed:
So add the getRelations method returning an array of possible transitions/relations:
public class Order implements HypermediaResource { public List<Relation> getRelations(Restfulie control) { if (status.equals("unpaid")) { control.relation("latest").uses(OrderingController.class).get(this); control.relation("cancel").uses(OrderingController.class).cancel(this); control.relation("payment").uses(OrderingController.class).pay(this,null); } return control.getRelations(); } }
3. Create your retrieval method:
@Get @Path("/order/{order.id}") public void get(Order order) { order = database.getOrder(order.getId()); result.use(xml()).from(order).include("items").serialize(); }
You are ready to go. Create a new order and access it through your /order/id path.
The best way to start is to download the sample application and go through the OrderingController and Order classes.
While most REST frameworks only support rendering xml out of the box, Restfulie already provides (through VRaptor and Spring) xml, xhtml and json representations of your resource. You can add new serializers as required. In order to take
content negotiation into play, simply use VRaptor’s representation() renderer:
@Get @Path("/order/{order.id}") public void get(Order order) { order = database.getOrder(order.getId()); result.use(representation()).from(order).include("items").serialize(); }
public class Order implements HypermediaResource { public List<Relation> getRelations(Restfulie control) { control.relation("up").at('http://caelumobjects.com'); return control.getRelations(); } }
Note that you can either create relations or transitions. We suggest clients to only use relations, but for clear semantics in some servers, you might want to invoke control.transition.
While typical JAX-RS services will deserialize your request body into your method argument and require you to retrieve extra URI information through the requested URI, Restfulie accepts one core parameter (based on its alias) and extra parameters to be extracted through the URI itself:
@Post @Path("/order/{order.id}/pay") @Consumes @Transition public void pay(Order order, Payment payment) { order = database.getOrder(order.getId()); order.pay(payment); status.ok(); }
Parameter support is provided through VRaptor, so Iogi and Paranamer support is already built-in.
To make an asynchronous request, you can use getAsync, postAsync, putAsync or deleteAsync methods. For that, you must provide a RequestCallback instance with a callback method implementation (the code to be executed when the response comes), like this:
RequestCallback requestCallback = new RequestCallback() { @Override public void callback(Response response) { // code to be executed when the response comes } }; Future<Response> future1 = Restfulie.at("http://www.caelum.com.br/clients").getAsync(requestCallback);
If you prefer, you can abbreviate it this way:
Future<Response> future1 = Restfulie.at("http://www.caelum.com.br/clients").getAsync(new RequestCallback() { @Override public void callback(Response response) { // code to be executed when the response comes } });
If you want Log4j to log the exceptions occurred when something goes wrong with the asynchronous request, you can create a log4j.xml configuration file on your classpath like this:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> <appender name="stdout" class="org.apache.log4j.ConsoleAppender"> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d{HH:mm:ss,SSS} %5p [%-20c{1}] %m%n"/> </layout> </appender> <category name="br.com.caelum.restfulie"> <priority value="ERROR" /> <appender-ref ref="stdout" /> </category> </log4j:configuration>
If you are looking for or want to help, let us know at the mailing list:
http://groups.google.com/group/restfulie-java
VRaptor’s website also contain its own mailing list which can be used to get help on implementing controller’s.
Restfulie was created and is maintained within Caelum by
Projetct Founder
- Guilherme Silveira ( email ) – twitter:http://www.twitter.com/guilhermecaelum
Contributors
- Lucas Cavalcanti (email) – twitter:http://www.twitter.com/lucascs
- Adriano Almeida (email) – twitter:http://www.twitter.com/adrianoalmeida7
- Samuel Portela (email) – twitter:http://www.twitter.com/samuel_portela
You can see an application’s source code, both client and server side were implemented using restfulie:
Users are encouraged to contribute with extra implementations for each layer (i.e. spring mvc implementation for the controller layer).
In its Java version, Restfulie uses by default:
- VRaptor:http://www.vraptor.org as the server-side controller
- XStream:“http://xstream.codehaus.org” as its serialization library
- java.net api for http requests
- Spring IoC for dependency injection
XStream is the most famous java serialization tool around with support both to json and xml while VRaptor (as Rails) supplies a reverse URI lookup system upon its controller which provides a way to identify URI’s from well defined transitions.
Check the license file