This is a pre-production deployment of Warehouse, however changes made here WILL affect the production instance of PyPI.
Latest Version Dependencies status unknown Test status unknown Test coverage unknown
Project Description

“REST APIs must be hypertext-driven”, Roy T. Fielding

Wait… Why?

The “Why” is pretty simple… there are an abundance of frameworks that make things RESTful by generating deterministic URLs for your database objects. Then you implement the popular HTTP methods to provide a nice way to interact with your newly minted resources. Congratulations, you have successfully mapped SQL into HTTP. The URL has become your WHERE clause and PUT, POST, and GET are synonyms for UPDATE, INSERT and SELECT.

So that is a very tongue-in-cheek answer for why did I feel the need to write this library. However it is not a great answer nor even an acceptable one in my opinion. The why is much more nuanced than that. The implementation that I just ranted about may indeed be quite RESTful but we need to know more about a solution than its URL structure and how it interprets various protocol actions before we can make that decision. This isn’t a dissertation on the Representation State Transfer architectural principles, I leave that to Dr. Fielding. This library attempts to provide a few mechanisms to make developing RESTful protocols simpler.


This library offers functionality that simplifies writing RESTful service implementations over an existing HTTP server stack such as Flask or Tornado. The HTTP stacks provide very clean and usable ways to construct URLs and route HTTP requests to specific chunks of code. I’m not going to implement that again. Instead, this library provides ways to embed hypermedia controls into your responses without introducing lots of nasty coupling in your application code.

This library is essentially an on-ramp to supporting Hypermedia Controls in your HTTP application. Hypermedia Controls referring to what is known as Level 3 of the Richardson Maturity Model. This model was described by Leonard Richardson at QCon in 2008 and has been further examined in Jim Webber’s most excellent REST in Practice. Here is a brief recap:

Level Zero

One URL, one HTTP method - POST. Document describes the function to invoke, parameters, etc. Response is the return value.

“There’s a little web-based peephole into some other universe, and you can only communicate wit the other universe by passing messages through the peephole.” - L. Richardson.

Level One: Resources

URLs identify resources but interactions are limited to sending a message that describes the function to invoke, parameters, etc. The interactions with different resources instances usually depend on URL patterns.

Level Two: HTTP

Resources are still identified by constructed URLs but interactions follow the rules of HTTP with respect to its verbs (methods). This is where most RESTful APIs stop.

Level Three: Hypermedia Controls

This is where the seldom understood and inpronouncable term HATEOAS shows up. Instead of the URL being formulated by the user of the service based on what they want to do and some URL pattern syntax, the available actions are represented directly in the document as named links. See REST APIs must by hypertext-driven for a well-written and relatively short rationale.

That is the part of the story that this library attempts to fill. It lets you write code like:

from hypermedia.tornado import mixins
from tornado import web

class PersonHandler(mixins.Linker, web.RequestHandler):

   def get(self, uid):
      person = get_person_information(uid)
      self.add_link('related-shows', SearchHandler, 'GET',
                    person_id=uid, type='shows')
      self.add_link('related-movies', SearchHandler, 'GET',
                    person_id=uid, type='movies')
      self.add_link('add-comment', CommentHandler, 'POST', uid=uid)
      self.add_link('comments', CommentHandler, 'GET', uid=uid)

      response = {}
      # ... build out the response
      response['links'] = self.get_link_map()


class SearchHandler(web.RequestHandler):

   def get(self):
      # processes query parameters

class CommentHandler(web.RequestHandler):

   def get(self, uid):
      # retrieve comments

   def post(self, uid):
      # add a comment

The hypermedia.tornado.mixins.Linker class takes care of constructing the appropriate links based on the registered handlers and makes them available via the get_link_map() method.

Release History

Release History


This version

History Node

TODO: Figure out how to actually get changelog content.

Changelog content for this version goes here.

Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Show More

Supported By

WebFaction WebFaction Technical Writing Elastic Elastic Search Pingdom Pingdom Monitoring Dyn Dyn DNS HPE HPE Development Sentry Sentry Error Logging CloudAMQP CloudAMQP RabbitMQ Heroku Heroku PaaS Kabu Creative Kabu Creative UX & Design Fastly Fastly CDN DigiCert DigiCert EV Certificate Rackspace Rackspace Cloud Servers DreamHost DreamHost Log Hosting