CycleServer includes an HTTP client library intended to make it easy to connect over RESTful interfaces. (It is modeled after the python rest-client library at http://code.google.com/p/python-rest-client.)

Example usage:

from application import restclient
c = restclient.connection("http://example.com/api", username="billg", password="ms")
response = c.request_get("/data")
print response.body()

Methods

restclient.generate_uri(url, parameters)
Returns a new URL with the given parameters added to the given URL.
The parameters argument can be either a dictionary, or a simple string with name-value pairs (eg, “name1=value1&name2=value2”).
Note that values in the dictionary are URL-encoded properly, but values in the simple string are assumed to be encoded already.
restclient.encode(value)
Returns the URL-encoded representation of the value.
restclient.decode(value)
Returns the decoded version of the given URL-encoded value.
restclient.connection(base_url, username, password, timeout)
Returns a connection object that will use the given base URL and authentication parameters (if given) for each request made on it.
The timeout (specified in seconds) defaults to 30 but can be overridden.

Connection methods

The following methods are available on the connection object:

request(url, body, headers, method, username, password)
Makes a request using the following method. Every parameter but url is optional.
As a shortcut, request_get(), request_post(), request_put(), request_delete(), and request_head() are available, taking all the same request() argument except method.
This returns a response object. If the connection times out, the status code is 1001.

Response methods

The following methods are available on the response object:

headers()
Returns a dictionary of headers in the response.
header(name)
Returns the value of the given header or None if it is not present.
body()
Returns the body as a string.
status()
Returns the HTTP status code.

Testing

You can test code that uses restclient. There is an alternate implementation automatically used in unit tests that lets you configure the connections and requests that should be made, and responds with the responses you give it in advance. This example asserts that the real code being tested will create one connection, and use that to make two requests, first to /test and then to /test2:

import plugintest
from application import restclient

class UpdateTimerTest(plugintest.TestCase):
  def test_valid(self):
    '''This represents a unit test you would write.'''
    # configure the expected connection with its base url...
    c = restclient.add("/base")
    # ...and tell it you want two requests to be made on it
    c.add(uri="/test", request_body="input", status=201, method="post", request_headers={"Content-Type": "text/plain" },
    response_body="output", response_headers={"CustomName": "CustomHeader"})
    c.add(uri="/test2", request_body="input", method="post", response_body="output")

    # now call the code under test
    connect()

    # make sure all the requests were done
    restclient.check_complete()

  def connect():
    '''This represents real code, in a separate file, that makes HTTP connections.'''
    c = restclient.connection("/base")

    # the first request is supposed to post to /test with "input" so this will succeed...
    response = c.request_post("/test", headers={"Content-Type": "text/plain"}, body="input")
    # ...and the responses are what the test supplied
    assert response.status() == 201
    assert response.body() == "output"
    assert response.header("CustomName") == "CustomHeader"

    # this line has a bug: the unit test above asserts that the second request was supposed to go to /test2, but this is going to /test
    response = c.request_post("/test", body="input")

Note that this does not use plugintest.HttpTestCase. That base class is only used for testing how real plugins will respond to HTTP requests, not testing that code that makes requests. You can test both at the same time, though, by using plugintest.HttpTestCase and instantiating your plugin that handles responses along with code that makes requests.