Skip to content

Latest commit

 

History

History
148 lines (116 loc) · 5.01 KB

content.rst

File metadata and controls

148 lines (116 loc) · 5.01 KB

Content Handling

The glinda.content module includes functions and classes that make content negotiation in Tornado easier to extend. Tornado's web framework includes ~tornado.web.RequestHandler.get_body_argument which handles a handful of body encodings. It is difficult to add new content type handlers in the current framework. Instead of adding all of the logic into the ~tornado.web.RequestHandler, glinda.content maintains a mapping from content type to encoder and decoder callables and exposes a mix-in that implements content negotiation over a ~tornado.web.RequestHandler.

The ~HandlerMixin.get_request_body method added by the HandlerMixin class will decode and cache the request body based on a set of registered content types. You register encoder and decoder functions associated with specific content types when your application starts up and the HandlerMixin will call them when it decodes the request body. Request bodies are exposed from Tornado as raw byte strings. Calling .register_binary_type associates binary transcoding functions with a specific MIME content type.

from glinda import content
import msgpack

content.register_binary_type('application/msgpack', msgpack.dumpb,
                             msgpack.loadb)

The transcoding functions are called to translate between dict and byte representations when the Content-Type header matches the specified value.

Many HTTP payloads are text-based and the protocol includes character set negotiation separately from the content type. The character set of the request body is usually indicated by the charset content parameter ala Content-Type: application/json; charset=utf-8. You can register string-based transcoding functions with .register_text_type. Request body processing will decode the byte string into a str instance according to the detected character set before calling text-based decoding functions. If a character set is not included in the request headers, then an application specified default value is used.

from glinda import content
import json

content.register_text_type('application/json', 'utf-8',
                           json.dumps, json.loads)

Binary registrations are preferred over text since they do not require the character transcoding process.

Once you have registered some content handlers, use the .HandlerMixin class to de-serialize requests and serialize responses. The following class mimics the GET and POST functionality of the excellent http://httpbin.org utility site.

../examples/contentneg.py

When you run examples/contentneg.py, it will run a Tornado application listening on port 8000 with at least the JSON content handler enabled. If the msgpack module is available, then the application/x-msgpack content type will be enabled. Likewise for the yaml module and application/yaml. Assuming that you have the PyYAML package installed, then the following examples should work.

A request that explicitly requests a JSON response will get one.

GET / HTTP/1.1
Accept: application/json
Accept-Encoding: gzip, deflate
Connection: keep-alive
Host: localhost:8000
User-Agent: HTTPie/0.9.2
HTTP/1.1 200 OK
Content-Length: 204
Content-Type: application/json; charset=utf-8
Date: Sun, 09 Aug 2015 17:00:30 GMT
Etag: "7bccfbf9d3f99b4b9bc88ec4f27b1913e5c0b27e"
Server: TornadoServer/4.2

{
    "args": {},
    "headers": {
        "Accept": "application/json",
        "Accept-Encoding": "gzip, deflate",
        "Connection": "keep-alive",
        "Host": "localhost:8000",
        "User-Agent": "HTTPie/0.9.2"
    },
    "origin": "::1",
    "url": "/"
}

If you explicitly request application/yaml, then the same data will be encoded as a YAML document.

GET / HTTP/1.1
Accept: application/yaml
Accept-Encoding: gzip, deflate
Connection: keep-alive
Host: localhost:8000
User-Agent: HTTPie/0.9.2
HTTP/1.1 200 OK
Content-Length: 174
Content-Type: application/yaml; charset=utf-8
Date: Sun, 09 Aug 2015 17:04:23 GMT
Etag: "3d88b7fc99bb1b31807e88e4ea3d312d391c037b"
Server: TornadoServer/4.2

args: {}
headers: {Accept: application/yaml, Accept-Encoding: 'gzip, deflate',
  Connection: keep-alive, Host: 'localhost:8000', User-Agent: HTTPie/0.9.2}
origin: ::1
url: /

The request handler simple needs to use HandlerMixin.get_request_body method to retrieve the request body and HandlerMixin.send_response to transmit a response body.

Functions

register_binary_type

register_text_type

clear_handlers

Classes

HandlerMixin