Skip to content

Latest commit

 

History

History
459 lines (312 loc) · 17 KB

README.textile

File metadata and controls

459 lines (312 loc) · 17 KB

Website

Check out Restfulie’s website if you still did not.

Restfulie: quit pretending

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.

Why would I use restfulie?

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

Could you compare it with other REST related APIs?

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.

More examples

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 .

Java or Ruby

Restfulie comes many different flavors, java and ruby.

One minute examples

Client side

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();

Server side

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();
	}

}

Installation

Download everything

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.

Client side installation

In order to use Restfulie in your client side app, simply add all required jars to your classpath.

Server side installation

Download vraptor’s blank project and configure your web.xml file. You are ready to go.

Client side usage

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.

Serialization configuration

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.

Caching

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.

Accessing all possible transitions

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.

HTTP verbs

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);
 

Sending some parameters

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);
 

More info

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.

Server side usage

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>

Relation/Transition invocation

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.

Typical example

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.

Content negotiation

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();
	}

Creating relations to other servers

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.

Accepting more than one argument

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.

Asynchronous Request

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
    }
});

Using Log4j to log exceptions from Asynchronous Request

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>

Getting help and mailing lists

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.

Team

Restfulie was created and is maintained within Caelum by

Projetct Founder

Contributors

Example

You can see an application’s source code, both client and server side were implemented using restfulie:

Contributing

Users are encouraged to contribute with extra implementations for each layer (i.e. spring mvc implementation for the controller layer).

Inner libraries

In its Java version, Restfulie uses by default:

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.

License

Check the license file