— Roy Fielding — 2000 • A RESTful architecture is an architecture that respects the following 6 constraints: • Client-Server • Stateless • Cacheable • Uniform Interface • Layered System • Code on Demand (optionally)
storage concerns, we improve the portability of the user interface across multiple platforms and improve scalability by simplifying the server components.
each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server. Session state is therefore kept entirely on the client.
to a request be implicitly or explicitly labeled as cacheable or non-cacheable. If a response is cacheable, then a client cache is given the right to reuse that response data for later, equivalent requests.
be composed of hierarchical layers by constraining component behavior such that each component cannot "see" beyond the immediate layer with which they are interacting.
architectural constraints are needed to guide the behavior of components. REST is defined by four interface constraints: identification of resources; manipulation of resources through representations; self-descriptive messages; and, hypermedia as the engine of application state.
• Fundamental for RESTful design • HTTP is the most famous REST architectural style. We are all used to: • HTTP verbs • URIs (uniform ressource identifier) • HTTP response (status, body)
Interface • they are resource-based: we’re talking about « things », not like in SOAP/RPC where we’re dealing with « actions » • resources are identified by URIs (multiple URIs can map to the same resource) • resources are NOT their representation • But they fail to be hypermedia
"previous_cursor": 0, "ids": [ 657693, 183709371, 7588892, 38895958, 22891211, 9019482, 14488353, 11750202, 12249, 9160152, ], "previous_cursor_str": "0", "next_cursor": 0, "next_cursor_str": "0" } What is the appropriate URL? How can I fetch the user info?
write assumptions (based on documentation) on resources locations • your client will be broken at the very moment the location has moved • strong coupling between client and server
are dynamically identified within hypermedia by the server (e.g., by hyperlinks within hypertext). • Except for simple fixed entry points to the application, a client does not assume that any particular action is available for any particular resources beyond those described in representations previously received from the server (in other words: a client does not require any prior knowledge to interact with any kind of application) • ideally, client is valid forever, just as browsers work (note the “ideally”)
to try to solve the hypermedia approach for APIs • Mime Types: HAL, Siren, JSON-LD, Atom+Pub, Collection+JSON • Description of available links/resources: RDF/ ALPS… • Much of the thinking around these hypermedia formats focuses on the way messages are designed.
<updated>2009-06-12T12:13:46Z</updated> <author> <name>Daffy</name> </author> <summary type="text" /> <content type="application/atom+xml;type=feed" src="http://example.org/my-new-collection"/> <link rel="edit" href="http://example.org/my-new-collection.atom" /> </entry> used to tell the client of this API where to edit this particular resource
a link “relation” • IANA defines a set of basic links relations (http:// www.iana.org/assignments/link-relations/link- relations.xhtml): about, next, edit, payment, related, up, version-history … • Sadly, you will need your own links definition.
"http://example.org/friends/", "links" : [], "items" : [], "queries" : [], "template" : { "data" : [] } } } Items of the collection How to query the collection How to create an item in my collection URL of this collection Relation to linked resources
@staticmethod def request(endpoint): return request("GET", BASE + endpoint).json() or {} def __init__(self, endpoint="/"): response = self.request(endpoint) for key in response.get('_links', {}).keys(): if key.startswith("ht:") : if isinstance(response['_links'][key], dict): with ignored(ValueError): setattr(self, key[3:], partial(HALClient, response['_links'][key]['href'])) if isinstance(response['_links'][key], list): for each in response['_links'][key]: with ignored(): title = each["title"] or "NONE" if isinstance(title, basestring): key = slugify(title, separator="_") if len(key) < 50: setattr(self, key, partial(HALClient, each['href']))
a classic MVC model • Where Hypermedia should be inserted? • the model: hypermedia controllers are independent from the models • view: “irrelevant” for APIS • controller! • based on Collection+JSON