Permalink
Fetching contributors…
Cannot retrieve contributors at this time
230 lines (154 sloc) 6.77 KB

JSON-RPC

:mod:`pyramid_rpc` supports JSON-RPC 2.0 Specification .

from pyramid.config import Configurator
from pyramid_rpc.jsonrpc import jsonrpc_method

@jsonrpc_method(endpoint='api')
def say_hello(request, name):
    return 'hello, %s!' % name

def main(global_conf, **settings):
    config = Configurator(settings=settings)
    config.include('pyramid_rpc.jsonrpc')
    config.add_jsonrpc_endpoint('api', '/api')
    config.scan(__name__)
    return config.make_wsgi_app()

if __name__ == '__main__':
    from wsgiref.simple_server import make_server
    app = main({})
    server = make_server('', 8080, app)
    server.serve_forever()

Setup

Use the includeme via :meth:`pyramid.config.Configurator.include`:

config.include('pyramid_rpc.jsonrpc')

Once activated, the following happens:

  1. The :meth:`pyramid_rpc.jsonrpc.add_jsonrpc_endpoint` directive is added to the config instance.
  2. The :meth:`pyramid_rpc.jsonrpc.add_jsonrpc_method` directive is added to the config instance.
  3. An exception view is registered for :class:`pyramid_rpc.jsonrpc.JsonRpcError` exceptions.

Usage

After including the pyramid_rpc.jsonrpc package in your project, you can add an :term:`endpoint` for handling incoming requests. After that, attach several methods to the endpoint to handle specific functions within your api.

Adding a JSON-RPC Endpoint

An :term:`endpoint` is added via the :func:`~pyramid_rpc.jsonrpc.add_jsonrpc_endpoint` directive on the config instance.

Example:

config = Configurator()
config.include('pyramid_rpc.jsonrpc')
config.add_jsonrpc_endpoint('api', '/api/jsonrpc')

It is possible to add multiple endpoints as well as pass extra arguments to :func:`~pyramid_rpc.jsonrpc.add_jsonrpc_endpoint` to handle traversal, which can assist in adding security to your RPC API.

Exposing JSON-RPC Methods

Methods on your API are exposed by attaching views to an :term:`endpoint`. Methods may be attached via the :func:`~pyramid_rpc.jsonrpc.add_jsonrpc_method` which is a thin wrapper around :meth:`pyramid.config.Configurator.add_view` method.

Example:

def say_hello(request, name):
    return 'Hello, ' + name

config.add_jsonrpc_method(say_hello, endpoint='api', method='say_hello')

If you prefer, you can use the :func:`~pyramid_rpc.jsonrpc.jsonrpc_method` view decorator to declare your methods closer to your actual code. Remember when using this lazy configuration technique, it's always necessary to call :meth:`pyramid.config.Configurator.scan` from within your setup code.

from pyramid_rpc.jsonrpc import jsonrpc_method

@jsonrpc_method(endpoint='api')
def say_hello(request, name):
    return 'Hello, ' + name

config.scan()

To set the RPC method to something other than the name of the view, specify the method parameter:

from pyramid_rpc.jsonrpc import jsonrpc_method

@jsonrpc_method(method='say_hello', endpoint='api')
def say_hello_view(request, name):
    return 'Hello, ' + name

config.scan()

Because methods are a thin layer around Pyramid's views, it is possible to add extra view predicates to the method, as well as permission requirements.

Handling JSON-RPC Batch Requests

Batch requests are handled automatically. A JSON-RPC batch request consists of an array of regular JSON-RPC requests; the response will consist of an array of the responses.

If there are no responses (which happens only when the request consisted entirely of notifications, to which there can be no response), the batch response is an empty body. This is not a valid JSON value, but the JSON-RPC spec does not provide for any other response in this situation.

Custom Renderers

By default, responses are rendered using the Python standard library's :func:`json.dumps`. This can be changed the same way any renderer is changed in Pyramid. See the Pyramid Renderers chapter for extra details. As an example, let's update an :term:`endpoint` to use Pyramid 1.4's cool new :class:`pyramid.renderers.JSON` renderer which supports custom adapters.

from pyramid.renderers import JSON

json_renderer = JSON()
json_renderer.add_adapter(datetime.datetime, lambda v, request: v.isoformat())
config.add_renderer('myjson', json_renderer)

config.add_jsonrpc_endpoint('api', '/api', default_renderer='myjson')

A default_renderer can be specified on an :term:`endpoint`, which will propagate to all methods attached to the endpoint. Optionally, an individual method can also override the renderer.

View Mappers

A view mapper is registered for JSON-RPC methods by default which will match the arguments from request.rpc_args to the parameters of the view. Optional arguments are allowed and an error will be returned if too many or too few arguments are supplied to the view.

This default view mapper may be overridden by setting the default_mapper option on :func:`~pyramid_rpc.jsonrpc.add_jsonrpc_endpoint` or the mapper option when using :func:`~pyramid_rpc.jsonrpc.jsonrpc_method` or :func:`~pyramid_rpc.jsonrpc.add_jsonrpc_method`.

HTTP GET and POST Support

As of pyramid_rpc version 0.5, JSON-RPC requests can be made using HTTP GET. By default, an endpoint will accept requests from both GET and POST methods. This can be controlled on either the :term:`endpoint` or on an individual method by using the request_method predicate. For example, to limit requests to only POST requests:

config.add_jsonrpc_endpoint('api', '/api', request_method='POST')

Batch requests are not supported via HTTP GET; there is no way to send multiple requests with the HTTP GET semantics.

Handling JSONP Requests

Pyramid comes with a :class:`pyramid.renderers.JSONP` which can be registered for the endpoint, using the method described within :ref:`jsonrpc_custom_renderers`.

API

Exceptions