(note: HTTP Callback replaces JSONRequest which had to be renamed due to a conflict with an existing project)

HTTP Callback

This article is in a Draft form. It should not be treated as canonical.

Introduction and Motivation

One common pattern that seems to come up building microapps is abstracting HTTP requests in a way that they can be stored, repeated, etc. Eg, a microapp that is in planning is a "cron" like app that will make requests to other microapps on a recurring basis. A first pass at designing the interface might look like this:

   % curl -X PUT -d "recurrence=hourly&url=http://app2.example.com/some/path/" http://cron.example.com/jobs/my-new-job/

And it would make a GET request to 'http://app2.example.com/some/path/' every hour. Of course, it's immediately obvious that we probably shouldn't limit things to GET requests. So next, we allow a method to be specified:

   % curl -X PUT -d "recurrence=hourly&method=POST&url=http://app2.example.com/some/path/" http://cron.example.com/jobs/my-new-job/

Then the cron app can make a POST (or PUT, or DELETE or whatever) request to the url every hour. But if you're making a POST or PUT request, you probably want some way to specify additional parameters (since they wouldn't go into the url), and maybe a body for the request, and even headers.

That's where this spec comes in. Since it seems to happen fairly often that a "request" needs to specified and stored somewhere or passed around between microapps, it should be useful to have a single, agreed upon format for them so that standard libraries and tools can be built to handle and process them. Essentially, a request object functions like a callback in a more traditional system.

This spec is an attempt to roughly standardize the request object that gets passed around and stored. If there is a single agreed-upon set of attributes, it should be possible to have tools and libraries to further simplify this type of pattern. Eg, converting between the HTTP Callback and different 'formats' like a WSGI environ dictionary, normalizing parameters, or integrating directly with HTTP/REST wrapper libraries like restclient.

Format

HTTPCallback attempts to be as close as possible to the XHR object that MochiKit uses but does not include the mimetype attribute that only makes sense within a javascript context. It also includes a couple extra attributes to support httplib2 type functionality (auth, redirect following) extensibility (kwargs), and forward-compatibility (version).

A HTTPCallback is a JSON Object with the following attributes:

attribute

type

default

description

url

string

URI to make the request to

method

string

'GET'

'GET', 'POST', 'PUT', 'DELETE', 'HEAD', or another HTTP verb.

queryString

string

url encoded key=value pairs seperated with '&'s. Should be automatically appended to the url if a GET request is made and placed in the body on any other method.

username

string

username to use for HTTP Auth.

password

string

password to use for HTTP Auth.

params

list/object

[]

JSON object of alternate parameters to be included. list of [key,value] pairs. alternately, an object with key : value pairs should also be accepted (but the list of tuples is preferred since an object/dictionary cannot handle repeated keys). Ultimately will be url encoded and added to the queryString.

body

string

request body. ignored on GET requests. if params are specified, body will be replaced with the www-formencoded version of the params.

headers

list

[]

list of key/value objects of HTTP headers to include. Content-Length and Host will be automatically set (and thus overwritten if they're included here) at the time the request is actually executed.

redirections

integer

5

maximum number of redirections to follow (see httplib2's param of the same name).

follow_all_redirects

boolean

False

by default, only "safe" redirects will be followed (ie, those on a GET method). set to true to allow redirects to be followed on other types of requests. again, see httplib2's param of the same name.

version

string

'0.1'

HTTPCallback version number. future-proofing the protocol. Libraries implementing future versions of HTTPCallback can look at this to detect an old format and act accordingly if non-backwards compatible changes are ever made to the spec.

kwargs

object

{}

additional key/value pairs. May be used by whatever app is processing the HTTPCallback object but will eventually be stripped out when the actual HTTP request is made. Useful if the actual HTTPCallback object is being passed around but MUST NOT make it out to the HTTP request.

The only required attribute is the url.

Typically, a request will be serialized to JSON for transmission. An XML or other representation should also be possible (and may be specified later).

Variable Substitution

Sometimes it's also useful for the application dealing with the request to be able to dynamically substitute in values for some of the parameters, etc. This spec should cover a standard way of specifying how those substitutions are carried out.

For substitution in the URI, the existing URI Template syntax should be used.

Substitution in the method should not be allowed (and wouldn't make much sense anyway).

Substitution in the params and headers may be possible. Probably using a syntax similar to URI Templates. Will require more thought.

The application executing the request should also be able to insert additional params and headers. Which params/headers are added and their values should be specified and documented on a per-application basis.

Examples

Some samples of HTTCallback objects and the rough HTTP request that would be generated from it. (note: Actual HTTP requests might include additional headers, etc. These examples are trying to just show the relevant ones).

Simplest Possible:

    {"url" : "http://www.example.com/foo"}
    
    GET /foo HTTP/1.1
    Host: www.example.com
    Content-Length: 0

Specifying a method:

     {"url" : "http://www.example.com/foo", "method" : "POST"}
     
     POST /foo HTTP/1.1
     Host: www.example.com
     Content-Length: 0

Specifying params:

     {"url" : "http://www.example.com/foo", "method" : "POST", "params" : {"foo" : "bar"}}
     
     POST /foo HTTP/1.1
     Host: www.example.com
     Content-Length: 7
     Content-Type: application/x-www-form-urlencoded
     
     foo=bar

With a queryString instead:

    {"url" : "http://www.example.com/foo","method" : "POST", "queryString" : "foo=bar"}

    POST /foo HTTP/1.1
    Host: www.example.com
    Content-Length: 7
    Content-Type: application/x-www-form-urlencoded

    foo=bar

Specifying params on a GET:

     {"url" : "http://www.example.com/foo", "method" : "GET", "params" : {"foo" : "bar"}}
     
     GET /foo?foo=bar HTTP/1.1
     Host: www.example.com
     Content-Length: 0

Or a queryString on a GET:

     {"url" : "http://www.example.com/foo", "method" : "GET", "queryString" : "foo=bar"}

     GET /foo?foo=bar HTTP/1.1
     Host: www.example.com
     Content-Length: 0

If both a queryString and params are specified, they get combined:

     {"url" : "http://www.example.com/foo", "method" : "POST", "queryString" : "foo=bar", "params" : [["baz","qux"]]}

     POST /foo HTTP/1.1
     Host: www.example.com
     Content-Length: 15
     Content-Type: application/x-www-form-urlencoded
     
     foo=bar&baz=qux

Specifying headers:

     {"url" : "http://www.example.com/foo", "headers" : [["Accept","text/*"]]}

     GET /foo HTTP/1.1
     Host: www.example.com
     Content-Length: 0
     Accept: text/*

Reference Implementation

There is a reference implementation of a HTTPCallback library for Python. It performs some of the basic normalization, can marshal into and out of python dictionaries, JSON strings, and WSGI environ dictionaries, and does basic URI Templating.

Open Issues

HTTP Callback (last edited 2007-10-13 10:16:19 by EtanWexler)