BT

RESTfulie - A Gem To Create Hypermedia Aware Services And Clients

by Dilip Krishnan on Nov 11, 2009 |

Guilherme Silveira writes to InfoQ on the release of a ruby gem that makes developing hypermedia aware services and clients that consume them a breeze. He said

Much has been spoken about what is and what are the advantages of using rest/restful ideas in one's application. Last year, Mark Baker wrote about hypermedia content in restful applications. There are also a few texts on more formal attempts to define HATEOAS and its advantages. Although being some good usage of the web in order to create web-based services, it is still missing the very best part of our every day life: hyperlinks and hypermedia content.

He goes on to describe an example of defining an order that goes through a well defined set of transitions for e.g. from example from unpaid to paid etc. It also allows the mapping of various transitions to a corresponding actions...

class Order < ActiveRecord::Base 
state :unpaid, :allow => [:latest, :pay, :cancel] state :cancelled, :allow => :latest transition :latest, {:action => :show} transition :cancel, {:action => :destroy}, :cancelled transition :pay, {}, :preparing end

Which generates, for example, an atom based resource representation that has embedded hypermedia:

<order> 
   <product>basic rails course</product> 
   <product>RESTful training</product> 
   <atom:link xmlns:atom="http://www.w3.org/2005/Atom" 
          href="http://www.caelum.com.br/orders/1" rel="latest" /> 
   <atom:link xmlns:atom="http://www.w3.org/2005/Atom" 
          href="http://www.caelum.com.br/orders/1/pay" rel="pay" /> 
   <atom:link xmlns:atom="http://www.w3.org/2005/Atom" 
          href="http://www.caelum.com.br/orders/1" rel="cancel" /> 
</order> 

And allowing the client to invoke dynamically created methods from consuming that resource representation:

order = Order.from_web 'http://caelum.com.br/orders/1' 
order.pay(payment) 

Jim Webber, on whose RESTBucks article and forthcoming REST book has been inspiration for the creation of this gem, said

The mulit-talented Guilherme Silveira with Adriano Almeida and Lucas Cavalcanti, has been coding up a storm on the RESTful services front. [...] More importantly, they’ve written up a generic client that can be used to explore that protocol. They’re hosting the demo service on GAE, and have released their code for all to enjoy on GitHub. Fabulous work guys, and very timely too

Savas Parastatidis, the co-author of the book had the following comment

I can’t wait for our book to finish so that everyone can check out our discussion of hypermedia and the stuff we’ve built. It’s really great to see Restfulie taking a very similar approach to ours.

Detailed examples of the gem usage for creating RESTful services and clients that consume those services are available at the GitHub project repository.

Hello stranger!

You need to Register an InfoQ account or or login to post comments. But there's so much more behind being registered.

Get the most out of the InfoQ experience.

Tell us what you think

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

I must be dreaming by Jean-Jacques Dubray

Hum... a cursory look at RESTfulie's examples (client code):
order = Order.from_web resource_uri

puts "Order price is #{order.price}"

order.pay payment # sends a post request to pay this order

order.cancel

What? Actions? Dilip, are you sure you gave us the right URL? That can't be RESTful?

More seriously, what have we gained from Web Services? How does a client "adapt" to a changing lifecycle (on the "server" side)?

It's kind of sad that for the last several years the RESTafarians have talked about the "uniform interface" and all we do now in RESTafaria is encoding actions behind the HTTP verbs. That's called progress? What a waste of time, what a bunch of boloney.

What's next? a contract? Ah no, they already have one...

class Order < ActiveRecord::Base
def following_transitions
transitions = []
transitions << [:show, {}]
transitions << [:destroy, {}] if can_cancel?
transitions << [:pay, {:id => id}] if can_pay?
transitions << [:show, {:controller => :payments, :payment_id => payment.id }] if paid?
transitions
end
end

On the positive side, it's good so see yet another evidence of the emergence of the state machine / entity lifecycle in connected systems.

Re: I must be dreaming by Dilip Krishnan

Everything doesn't have to be a REST vs. SOAP debate :)
More seriously, what have we gained from Web Services? How does a client "adapt" to a changing lifecycle (on the "server" side)

For one, the client no longer relies on "cool urls" and the server can "guide" the clients as the service as it progresses thru' the business process. Its WS-* speak its similar to using a UDDI service to provide an indirection for service locators, only a much lighter weight way of doing it.

On the question of what has been gained from web services, I would say the fact that we can have an object oriented programming model via some ruby meta-programming magic. Tho' whether thats a good thing or not is debatable.

Re: I must be dreaming by Dilip Krishnan

What? Actions? Dilip, are you sure you gave us the right URL? That can't be RESTful?

The link to the gem has been updated. Thank you for pointing that out.

Re: I must be dreaming by Jean-Jacques Dubray

Could you elaborate on what it means for a programmatic client to be "guided"? do you imply that somehow the server can change the order lifecycle and the client code will somehow know what to do? that sounds like science fiction.

Re: I must be dreaming by Dilip Krishnan

Could you elaborate on what it means for a programmatic client to be "guided"?

If you take the following example say you GET an order which is in a particular state that allows you to pay or cancel (demonstrated by the link/rel)

<order>
<product>basic rails course</product>
<product>RESTful training</product>
<atom:link xmlns:atom="http://www.w3.org/2005/Atom"
href="http://www.caelum.com.br/orders/1" rel="latest" />
<atom:link xmlns:atom="http://www.w3.org/2005/Atom"
href="http://www.caelum.com.br/orders/1/pay" rel="pay" />
<atom:link xmlns:atom="http://www.w3.org/2005/Atom"
href="http://www.caelum.com.br/orders/1" rel="cancel" />
</order>

If the seller decides to offer a coupon perhaps, for orders that meet a certain criteria; then they could add another transition. Or if the service changes the tracking uri. When the client GETs the latest order for tracking he/she sees a new available "action" and uri.

<order>
<product>basic rails course</product>
<product>RESTful training</product>
<atom:link xmlns:atom="http://www.w3.org/2005/Atom"
>href="http://www.newcaelum.com.br/orders/1" rel="latest" />
<atom:link xmlns:atom="http://www.w3.org/2005/Atom"
href="http://www.caelum.com.br/orders/1/pay" rel="pay" />
<atom:link xmlns:atom="http://www.w3.org/2005/Atom"
href="http://www.caelum.com.br/coupon/23456" rel="coupon" />

<atom:link xmlns:atom="http://www.w3.org/2005/Atom"
href="http://www.caelum.com.br/orders/1" rel="cancel" />
</order>

This is what I mean buy guide.
do you imply that somehow the server can change the order lifecycle and the client code will somehow know what to do? that sounds like science fiction.

The intention is not to imply that this is a mechanism to automate client interactions, for e.g. if a BOT were tasked to place 20 orders, they will not suddenly recognize that the order lifecycle has a new coupon linked to it and know exactly what to do about it and alter behavior on the fly. That would be science fiction :)

The implication is just that the client is not bound to a particular lifecycle uri. After the initial request the service can guide the clients navigation accross the "known" business process states. The client would still break if the lifecycle were to change for e.g if we add an approval process to the order after its paid etc.

Re: I must be dreaming by Jean-Jacques Dubray

Dilip:

thanks for the precisions.

>> The intention is not to imply that this is a mechanism to automate client interactions
makes sense

>> The implication is just that the client is not bound to a particular lifecycle uri.
No sure I am following what you are saying, again, assuming that actions are well known to both the client and server, I am not sure clients would easily invoke these actions on dynamic endpoints. This presents such a security threat (injection) that you would think no one in their right mind would want to do that.

Re: I must be dreaming by Dilip Krishnan


No sure I am following what you are saying

For some reason my formatting isnt showing up in firefox... but notice how the "latest" action is now www.newcaelum.com.br/orders/1 in the second listing. Consequently the server has now changed the uri to access the "latest" orders without affecting the client. May not be the best example, but it shows how the server can evolve independently from the client, thus removing the coupling of the client to the action uri.
This presents such a security threat (injection) that you would think no one in their right mind would want to do that.

The example is probably not elaborate enough to account for security scenarios, which will most likely involve SSL/OAuth etc. Having take care of that how is this any different from an ESB?

Re: I must be dreaming by Jean-Jacques Dubray

ok, I see your point, it helps soften the problem that REST introduced when access is coupled with identity. Here "access" can be introspected for a given identity.

I was hoping a less mundane application of HATEOAS, but I guess we agree that when the client is a software agent, there is not much that can be done in terms of adapting to changing states and transitions.

In the end, there is no gain with respect to Web Services, since we are just changing the encoding of the actions. We have circled back where we started, wasting a couple of years in the process and pushing countless people to CRUD. Now, they can invoke actions again. What a progress.

I suggest we could give a hint to the server with a custom HTTP header called RESTaction... We could also suggest a totally new and cool pattern, the wrapped resource representation (WRR) pattern whereby we wrap the resource representation that we post as part of an action invocation with a root element which is named after the action we invoke. That way we keep everything conveniently in one document for further downstream processing. That way we could actually route the action invocation in the back-end, rather than always wiring it to a Java or C# method.

Of course, by using REST we have lost everything else such as bi-directional interfaces, asynchrony, assemblies, orchestration... but who cares?

I would strongly encourage Guilherme to explain how "events" fit in the picture. The good news is that Guilherme understands the concept of a resource lifecycle and the difference with a business process (unlike Jim and Savas). Since a resource lifecycle is made up of states and events are the occurence of a state, how can REST handle events? Again, minor (and rather annoying) architecture detail.

Re: I must be dreaming by Guilherme Silveira

Hello Jean-Jaques,

I am sorry about the delayed (and long) response.

In the end, there is no gain with respect to Web Services, since we are just changing the encoding of the actions.

I believe that even if, in the end, the result would be the same, one can not say that taking different paths to achieve the same result is the same and therefore a waste of years of research.

If that was true, why would other companies try to build cars when we already have american ones doing so? They have the technology and it would be enough if they provide us all with it: we would drive our cars - as we do today.
But koreans, japaneses, germans, chineses, french... have also their own cars, which have the same goal in mind... are we back at the same place?

The process that allows us to create different solutions for the same problems is the basis of innovation.

And it is true not only for private-research based technology as cars, but with open ones too.

If the world was a place where people would just adopt one solution and never try creating different ones for the same type of problem, corba could be the only solution for distributed systems and, following that line of thought, why would someone ever try webservices? After all, corba might solve your problems... but what would happen then? You would have to adapt your system to corba's limitations or adapt corba to your system's limitations. In the end, you would have your system up and running, but the process that took you there brought you new choices that might be cheaper and faster (or cost more and slower) than the already existing ones.

The same holds for programming languages and pretty much every other possible human evolution: we could still be living with the same technology from the 80's... but everything would have a much higher cost, being therefore less profitable and scalable (thinking about humankind reach).

Summing up, even if in the end, two ideas (web services and what has been debated), achieve the same goal, the pure existence and its competitors development process allows technologies to evolve.

An old technology which does not get ideas from others upcoming ones is faded to be outdated.

We have circled back where we started, wasting a couple of years in the process and pushing countless people to CRUD. Now, they can invoke actions again. What a progress.


Therefore I am afraid I can not agree with this sentence. There is no waste of research or money even if the result was exactly the same.

But again, the result is not the same: it involves costs, time-to-production, quality of code and so on. And that's where I believe we might be helping.

Creating a system using a full WS-stack nowadays still takes a lot of effort although some technologies (as soap4r) can really help you out.

Restfulie might help projects pretty much in the same way that SpringMVC does in the Java web frameworks path. It is not an commitee-based standardized implementation, but it helps companies on the whole world solve their problems. As there is space for Spring MVC and JSR-based framework implementations on the market, WS-stack-based and restfulie (or any other framework) based solutions can help our clients solve their problems, we just have to use the one that fits better depending on the client's reality.

Regards

Guilherme

Re: I must be dreaming by Guilherme Silveira

Hello Dilip!

Again, sorry for the delayed response...

Having take care of that how is this any different from an ESB?


I believe your question shows one of the big issues on the previous response. I will try to ellaborate it here.

Even if the resulting system works the same way as if I had chosen another language, technology or bought a complete solution, the process that took me there varies.

I can have my team improve their coding skills, tools-usage or have them learn a new technology while solving my companie's problem by implementing the solution. The result is the same, but the money spent, time requirement and my client's company intellectual growth depends on the technology I will choose.

If one believes that both lead to the same solution (I don't but there is no need to argue), there is still no need to show the key points that differ on implementing a solution using restfulie, java RMI, http based cruds or a BPM/BPEL solution as they are quite clear: the code, the tools, the languages in which the system is described, everything differs.


Regards

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

10 Discuss

Educational Content

General Feedback
Bugs
Advertising
Editorial
InfoQ.com and all content copyright © 2006-2014 C4Media Inc. InfoQ.com hosted at Contegix, the best ISP we've ever worked with.
Privacy policy
BT