Guilhermesilveira's Blog

as random as it gets

Posts Tagged ‘atom

Restfulie 0.5, atom feeds, content negotiation and default controllers

leave a comment »

ATOM FEED

Restfulie 0.5.0 is out and its major new feature is its support to Atom feeds with variable media types.

A feed can be easily rendered by invoking the to_atom method:


@hotels = Hotel.all
render :content_type => 'application/atom+xml',
:text => @hotels.to_atom(:title=>'Hotels', :controller => self)

A collection might contain entries with different media types and each one will be rendered in its own way. The client code works as any other usual client would, note that there is still content negotiation taking place:


hotels = Restfulie.at('http://localhost:3000/hotels').get
puts hotels[0].name
puts hotels[1].name

And using hypermedia to drive our business, deleting an entry will send a DELETE request to that entry’s self URI:


Restfulie.at('http://localhost:3000/hotels').get.each do |h|
h.delete if h.city=="Sao Paulo"
end

In future releases we expect to support atom feed generation (and consuming) through Ratom.

CONTENT TYPE

Another easy to use feature is content type negotiation, which also happens when rendering a single resource:


@hotel = Hotel.find(params[:id])
render_resource @hotel

Users can now extend Restfulie in order to create custom formats (not based on json/xml/xhtml related media types)

CLIENT SIDE

Entry points have been extended and now they can be reached even if there is no class representing the received information in the client side:


support Restfulie.at('http://localhost:3000/cities').create(city)
Restfulie.at('http://localhost:3000/cities/5').get

One can also access the web response:

response = Restfulie.at('http://localhost:3000/cities/5').get.web_response

And play with content negotiation:


Restfulie.at(uri).accepts('media-type').get
Restfulie.at(uri).as('media-type').create(something)

DEFAULT CONTROLLERS

In the server side, a generic controller has been created which supports show, delete and create by default.

There is also a new method called render_created that can be used in order to answer a request with a 201 Created response and its resource location.

WEBSITE

Restfulie got its own website and all Ruby docs have been migrated.

Thanks to all the team and collaborators!

If you look carefully, you might find out next week’s upcoming news.

Advertisements

Written by guilhermesilveira

January 7, 2010 at 9:30 am

Hypermedia: making it easier to create dynamic contracts

with 4 comments

The human web and christmas gifts

You have been buying books at amazon.com for 5 years now: typing http://www.amazon.com in your browser, searching for your book, adding it to the cart and entering your credit card information.

But this year, on December 15th 2009 something new happens. Amazon has launched an entire new “christmas discount program” and in their front page there is a huge ad notifying their clients about this new item.

How do you react?

“Contract violated! I am not buying anything today.”

The key issue in loosely coupled systems is the ability to evolve one side without implying in any modifications on the other part.

As some Rest guys agree, hypermedia content was the factor which allowed such situations to happen in the human web without clients screaming “i don’t know what to do now that there is a black friday clearance!” or “there is a new link in this page, let me email the ‘webmaster’ and complain about it“.

In the human web, some contracts are agreed upon and validated through end-to-end tests. Some companies will use tools as selenium-rc, webdriver or cucumber to drive their tests and ensure that expected behaviour by their clients does not break with a new release of their software.

Those tests do not validate all content, though, giving space for what is called forward-compatibility: the system is free to create new functionalities without breaking previous expected behaviour.

But my rest-client is not human

In the non-human web, the most well known media type used is xml, although not hypermedia-capable. There are a couple of ways to create forward or backward-compatible schemas that check xml structures, but – unfortunately – usually
fixed schemas will not invest part of its contract in order to making it forward-compatible
: its an optional feature.

One option is to create “polymorphic” types through xsd schemas, which will get nasty if your system evolves continuously – not once every year – and you find yourself in a schema-hell situation.

One easy solution is to accept anything in too many places, which seems odd.

What are we missing then? According to Subbu Allamaraju, in RESTful applications, “only a part of the contract can be described statically, and the rest is dynamic and contextual”: you tell your client that they can believe you will not break the statically contract – you might use some schema validation to do that – and it’s up to you on the server side to not do it on the dynamic part.

Some might think it sounds too loose… let’s recall the human web again:

  • xhtml allows you to validate your system’s fixed contract
  • it’s up to you not to remove an important form used throughout the buying process

So, what are the dynamic parts of my “contract”?

In a RESTful application the contract depends on its context, which is highly affected by three distinct components:

1. your resource’s state

If a person had his application denied to open an account, your resource representation will not offer a “create_loan” request. A denied application is an information regarding its state.

While your company and application evolves, its common to find ourselves in a position where new states appear.

2. your resource’s relations

In a book store (i.e. amazon a few years ago), a book might have a category associated with it so you can access other similar books:

<book>
<name>Rest if you do not want to get tired</name>
<link rel="category" href="http://www.caelumobjects.com/categories/self-help" />
</book>
A couple years later, your system might add extra relations, as "clients which bought this book also recommend"

<book>
 <name>Rest if you do not want to get tired</name>
 <link rel="category" href="http://www.caelumobjects.com/categories/self-help" />
 <link rel="recommendation" href="http://www.caelumobjects.com/books/take-a-shower-with-a-good-soap-if-you-need-to-rest" />
</book>

When your company and application evolves, its common to find ourselves in a position where new relations appear.

3. your resource’s operations

In a REST application, your resource operation’s are represented by HTTP verbs: supporting a new one will not affect clients which use all other available verbs so far.

In the RPC/Webservices world, new operations would be implemented creating new remote procedures or services.

But how can my clients be sure that I will not break the dynamic contract?

Pretty much in the same way that you do in the human web: it’s your word.

In the human web, how do we guarantee that we will not remove or break some functionality the user expects to be there? We end-to-end automatically test its behaviour.
Our word (our tests) is the only reason to rest without worries that we will not break our client’s expectations. The same holds on the non-human web.

The dynamic contract should be throughly tested in order to not break our client’s expectations.

There are other approaches (as client-aware contracts) which might add some extra coupling between both sides.

HTTP+XML+ATOM gives us the possibility to work with both the fixed (schema validated) and dynamic (test validated) contract.

As Bill Burke pointed in a comment, “you can design your XML schemas to be both flexible and backward compatible ” and “companies, users, developers desire this contract”.

That’s the good points of using schemas, but its not everyone that use them in a flexible and backward compatible way. Even those who use might have a little bit of hard time to support it, i.e. having to maintain more than one entry point for each version of their schemas.

That’s when we can use the good points of the schema validation, as Bill pointed out, with the easy evolution advantages of a dynamic contract: as we do in the human web.

By using dynamic contracts as xml+atom following the Must Ignore rules, forward and backward compatibility is gained by default, independent on what the user does – assuming that tests are a must in any solution.

Dynamic contracts also give hints for frameworks, as they guide you on what your user can and can not do or access, but maybe not for tools, in a different fashion of what fixed contracts do: with a fixed schema I would be able to pre-generate my classes, while with dynamic schemas I the framework inject methods.

That’s why we try to take an approach which force programmers to adopt xml+atom. The entry point on the Restfulie framework is loosely evolution.

Its first example, the documentation and its examples do not focus on how easy it is to use nice URIs and the 4 most famous http verbs, but how easy it is to evolve your system using hypermedia and http: uri’s come soon afterwards.

And it seems to be working fine to far, the first developers using it in live systems have already supported hypermedia content as a way to guide clients through their systems.

Restfulie support in dynamic contracts

Matt pulver’s extension to Rails allows one to instantiate types with regards to their active record relations and attributes, but it requires every xml element to be present (strong coupling to the data structure presented by the server).

Using Jeokkarak (korean hashis), Restfulie instantiate objects matching your local data structure, supporting fields defined in your attributes and inserting extra fields for those elements unknown to your model.

For example, if you have a model as:

class Bill
  attr_accessor :value, :to_date
end

And the following xml:

<bill>
  <value>100</value>
  <to-date>10/10/2010</to-date>
  <taxes>0.07</taxes>
</bill>

The result is a dynamic object capable of answering to:

bill = Bill.from_web uri
puts bill.value 
puts bill.to_date
puts bill.taxes

If your model was ready to accept such xml, Restfulie will do the job, whilst if it doesn’t recognize the attribute, it will still be available to you.

That’s the default Restfulie behaviour: to allow the other part to evolve their dynamic contract (and even parts of the fixed one) by default, without any extra effort from your side.

Written by guilhermesilveira

December 8, 2009 at 9:26 am