Line 260: | Line 260: | ||
* [http://tech.groups.yahoo.com/group/rest-discuss/ rest-discuss@yahoogroups.com] | * [http://tech.groups.yahoo.com/group/rest-discuss/ rest-discuss@yahoogroups.com] | ||
* [http://www.redhat.com/mailman/listinfo/rest-practices/ rest-practices@redhat.com] | * [http://www.redhat.com/mailman/listinfo/rest-practices/ rest-practices@redhat.com] | ||
* [ | * [http://lists.sourceforge.net/lists/listinfo/resteasy-developers resteasy-developers@lists.sourceforge.net] | ||
* [http://fedorahosted.org/mailman/listinfo/rhevm-api rhevm-api@lists.fedorahosted.org] | * [http://fedorahosted.org/mailman/listinfo/rhevm-api rhevm-api@lists.fedorahosted.org] |
Revision as of 19:57, 27 April 2010
Cloud APIs REST Style Guide
Introduction to REST
REST (REpresentional State Transfer) is a distributed computing style formalized by Roy Fielding in his doctoral dissertation. Fielding studied the architectural successes of the web and generalized his findings into a set of design principles that can be applied to other distributed hypermedia systems.
REST proposes several principles including:
- Each resource is addressable by a URI
- Resources are manipulated via their representations (e.g. XML, HTML, JSON, YAML etc.)
- A uniform interface is exposed for all resources (GET, PUT, POST, DELETE etc. in the case of HTTP)
- Messages are self-descriptive - i.e. each message contains everything necessary for a stateless server to process it
- Hypermedia as the engine of application state (HATEOAS) - state transitions (e.g. changing a resource's state or examining a related resource) is driven by the hypermedia representation of the resource itself
By applying these principles to web services in general, it is hoped that web services will gain some of the desirable properties of the web such as horizontal scalability, de-coupled clients and servers, reduced latency through the use of proxies and real interoperability.
Another very real feature of RESTful APIs are their simplicity and familiarity of use. With any RESTful API, it should be relatively trivial to point a simple client (e.g. curl in a shell script) at a URI for the API and quickly build something useful. This makes a refeshing change from heavyweight middleware frameworks such as CORBA or WS-*.
A Word on HATEOAS
Hypermedia as the engine of application state is one of the REST principles which folks can struggle to get to grips with.
HATEOAS means that the hypermedia guides the clients' interactions. In other words, the hypermedia responses from the API contain links which the client can follow in order to make further requests. This also implies that the URI structure is not part of the API so the client does not manually construct URIs and the server is free to change its URI structure in future.
If you find that you are documenting the URI structure and explaining how clients should construct a URI, you are likely breaking this principle.
Purpose of this Style Guide
This document has two purposes:
- Give straightforward answers to some the questions every RESTful API designer gets bogged down in.
- Document consensus amongst the various API projects related to Red Hat's cloud stack.
The idea is that rather having each of these projects individually trip over the many hurdles associated with RESTful API design, we will collectively address each of the issues and come to some form of rough consensus (gasp!). And hopefully, not only will we save ourselves a few ulsers, but we will also end up with a set of APIs that look somewhat consistent.
This is a wiki, so feel free to edit it. If you want to make a more controversial change, or there is something here you don't like, fire off an email to the rest-practices mailing list.
Guidelines
Each of the below sections tries to advise you, the API designer, on the consensus style for our cloud related APIs.
Where appropriate, there will be link a relevant discussion on the rest-practices mailing list. Where the subject is still under discussion, that will be called out. Where multiple acceptable approaches have been proposed with no great controversy, then the approach which matches any of our existing APIs will be used.
XML Style
Okay, let's start with something easy (hah!) - naming conventions for elements and attributes on our XML representation of resources.
We have three options:
- CamelCase/studlyCaps - Java coding style
- lowercase_underscore - python coding style
- lowercase-hyphen - perhaps more common in XML
The latter option isn't so great where the identifiers are mapped into programming language identifiers. CamelCase is nice for Java implementations, but lowercase_underscore just looks better in XML/JSON/etc.
Example:
<customer_order product_type="book"> <book href="..."/> ... </customer_order>
URL Style
URLs should be alllowercasewithnopunctuation e.g.
http://foo.com/dublintours/guinnessstorehouse/
Entry Point
As implied by HATEAOS, each API should strive for a single entry point URI.
Where there is a natural top-level object or collection represented by the API, this can be the resource addressed by the entry point. That resource will then have links with which the client can navigate to all other resources.
In other cases, the top-level URI should merely return an "api" resource with links to the other resources or collection of resources in the API e.g.
GET / HTTP/1.1 Host: {host} HTTP/1.1 200 OK Content-Type: application/xml Content-Length: {length} <api> <link rel="books" href="/books"/> <link rel="music" href="/music"/> <link rel="orders" href="/orders"/> </api>
The client uses its knowledge of the API's link relation types to decide which URI it needs.
XML Schema
RESTful services should be representation-oriented. This means you should pay close attention to the representation of the service's resources.
The default representation of resources in our APIs is XML. Each API should have an XML schema (or RNG schema) which clients and the server alike can use to validate their XML output in their test suites. Deployed servers should not validate client input using this schema so that newer clients may continue to work with older servers.
In the case of a Java server using JAX-RS, it makes good sense to start with a schema of the representation and use xjc to generate JAX-B annotated classes. This ensures your design focus is on the XML representation rather than the object model in the code.
JSON
Describe our mapping of XML to JSON.
YAML
Describe our mapping of YAML to JSON.
Compatibility and Versioning
Once released, all cloud APIs should make an API stability guarantee. Resource representations may be extended, but it must be in a backwards compatibile manner - i.e. old client works with new server.
If at any point in the API evolution a backwards incompatible change must be made, then a new link relation type should be added to support the new incompatible representation and the old relation type should be retained e.g.
<api> <link rel="books_v2" href="/books/v2/"/> <link rel="books_v2" href="/books"/> <link rel="music" href="/music"/> <link rel="orders" href="/orders"/> </api>
FIXME: discuss the option of using content type negotiation based on versioned media types for this.
Documentation
APIs should be documented. Suggest a documentation style.
Links
Link headers - appropriate when an entity body can only contain a single link of a given relation type.
Href attributes - appropriate for object relationships (e.g. {{{<order><book href="..."/>}}})
Atom links - approriate for blocks of action links?
Recommend concatenating multiple link headers together.
URIs for our custom relations: Applications that don't wish to register a relation type can use an extension relation type, which is a URI [RFC3986 that uniquely identifies the relation type] versus bburke
References:
Media Types
Encodes more detail of the application protocol in the headers, rather than the request/reponse bodies.
If we use media types, we should continue to support application/xml, application/json, application/x-yaml.
Use of media types for versioning?
Scope of the media types? Take a look at e.g. the Sun Cloud API's set of media types.
Naming of our media types.
Use of +json and +yaml modifiers.
References:
Read-Only Fields
- Ignore changes to read-only fields
- Return an error if PUT/POSTed doc includes a read-only field
- Return an error if PUT/POSTed doc includes a change to a read-only field
(1) means we're not being clear on semantics.
(2) is too restrictive on clients that want to do a GET, make a minor change with xpath and then PUT the result.
(3) works, except for an often changing read-only value (e.g. free disk space).
Our pragmatic approach combines (1) and (3).
References:
Query Parameters
Allow servers to instruct clients on how to construct appropriate URIs, such as is done in HTML forms and URI templates, by defining those instructions within media types and link relations?
Actions
Async Operations
References:
Caching
Updates Monitoring
Errors
WADL
Language/Platform Considerations
Most of our APIs are implemented using:
- Java, JBoss, JAX-RS, RESTeasy
- Ruby, Rails, Sinatra, ActiveResource, ...
REST makes the interoperability question mostly straightforward, but we should be mindful about not making things too awkward for a certain core set of clients:
- Shell script using e.g. curl
- Java (which client API do we recommend)
- Ruby
- Python
Java
RESTeasy's Client Proxy Framework has the advantage that the server-side JAX-RS annotated interfaces can be re-used, but this also presents a problem. By using the proxy framework, a client embeds knowledge of the URI structure and, as such, is susceptible to future changes in the URI structure. For that reason, using this framework is discouraged except for quick n' dirty clients that aren't worried about future changes to the API.
Further Resources
Books
Blogs
- How I explained REST to my wife
- REST APIs must be hypertext-driven (rfielding)
- It is okay to use POST (rfielding)
- REST core values (bburke)
- Modeling operations in REST (bburke)
- To WADL or not to WADL (bburke)
- MediaType as Your IDL (bburke)
RESTful Cloud APIs
Other RESTful APIs
- [http://tools.ietf.org/html/rfc5023 The Atom publishing
- REST-*
- Sun Cloud APIs