Welcome to typedjsonrpc’s documentation!¶
Contents:
typedjsonrpc¶
typedjsonrpc is a decorator-based JSON-RPC library for Python that exposes parameter and return types. It is influenced by Flask JSON-RPC but has some key differences:
typedjsonrpc...
- allows return type checking
- focuses on easy debugging
These docs are also available on Read the Docs.
Using typedjsonrpc¶
Project setup¶
To include typedjsonrpc in your project, use:
from typedjsonrpc.registry import Registry
from typedjsonrpc.server import Server
registry = Registry()
server = Server(registry)
The registry will keep track of methods that are available for JSON-RPC. Whenever you annotate
a method, it will be added to the registry. You can always use the method rpc.describe()
to get
a description of all available methods. Server
is a
WSGI compatible app that handles requests. Server
also has a development mode that can be run using server.run(host, port)
.
Example usage¶
Annotate your methods to make them accessible and provide type information:
@registry.method(returns=int, a=int, b=int)
def add(a, b):
return a + b
@registry.method(returns=str, a=str, b=str)
def concat(a, b):
return a + b
The return type has to be declared using the returns
keyword. For methods that don’t return
anything, you can use either type(None)
or just None
:
@registry.method(returns=type(None), a=str)
def foo(a):
print(a)
@registry.method(returns=None, a=int)
def bar(a):
print(5 * a)
You can use any of the basic JSON types:
JSON type | Python type |
---|---|
string | basestring (Python 2), str (Python 3) |
number | int, float |
null | None |
boolean | bool |
array | list |
object | dict |
Your functions may also accept *args
and **kwargs
, but you cannot declare their types. So
the correct way to use these would be:
@registry.method(a=str)
def foo(a, *args, **kwargs):
return a + str(args) + str(kwargs)
To check that everything is running properly, try (assuming add
is declared in your main
module):
$ curl -XPOST http://<host>:<port>/api -d @- <<EOF
{
"jsonrpc": "2.0",
"method": "__main__.add",
"params": {
"a": 5,
"b": 7
},
"id": "foo"
}
EOF
{
"jsonrpc": "2.0",
"id": "foo",
"result": 12
}
Passing any non-integer arguments into add
will raise a InvalidParamsError
.
Batching¶
You can send a list of JSON-RPC request objects as one request and will receive a list of JSON-RPC
response objects in return. These response objects can be mapped back to the request objects using
the id
. Here’s an example of calling the add
method with two sets of parameters:
$ curl -XPOST http://<host>:<port>/api -d @- <<EOF
[
{
"jsonrpc": "2.0",
"method": "__main__.add",
"params": {
"a": 5,
"b": 7
},
"id": "foo"
}, {
"jsonrpc": "2.0",
"method": "__main__.add",
"params": {
"a": 42,
"b": 1337
},
"id": "bar"
}
]
EOF
[
{
"jsonrpc": "2.0",
"id": "foo",
"result": 12
}, {
"jsonrpc": "2.0",
"id": "bar",
"result": 1379
}
]
Debugging¶
If you create the registry with the parameter debug=True
, you’ll be able to use
werkzeug’s debugger. In that case, if there is an
error during execution - e.g. you tried to use a string as one of the parameters for add
- the
response will contain an error object with a debug_url
:
$ curl -XPOST http://<host>:<port>/api -d @- <<EOF
{
"jsonrpc": "2.0",
"method": "__main__.add",
"params": {
"a": 42,
"b": "hello"
},
"id": "bar"
}
EOF
{
"jsonrpc": "2.0",
"id": "bar",
"error": {
"message": "Invalid params",
"code": -32602,
"data": {
"message": "Value 'hello' for parameter 'b' is not of expected type <type 'int'>.",
"debug_url": "/debug/1234567890"
}
}
}
This tells you to find the traceback interpreter at <host>:<port>/debug/1234567890
.
Additional features¶
Customizing type serialization¶
If you would like to serialize custom types, you can set the json_encoder
and json_decoder
attributes on Server
to your own custom json.JSONEncoder
and json.JSONDecoder
instance. By default, we use the default encoder and decoder.
Adding hooks before the first request¶
You can add functions to run before the first request is called. This can be useful for some special setup you need for your WSGI app. For example, you can register a function to print debugging information before your first request:
import datetime
from typedjsonrpc.registry import Registry
from typedjsonrpc.server import Server
registry = Registry()
server = Server(registry)
def print_time():
now = datetime.datetime.now()
print("Handling first request at: {}".format(now))
server.register_before_first_request(print_time)
Accessing the HTTP request from JSON-RPC methods¶
In some situations, you may want to access the HTTP request from your JSON-RPC method. For example,
you could need to perform logic based on headers in the request. In the typedjsonrpc.server
module, there is a special typedjsonrpc.server.current_request
attribute which allows you to
access the HTTP request which was used to call the current method.
Warning
current_request
is implemented as a thread-local. If you attempt to call
Server.wsgi_app
from Registry.method
, then current_request
will be overriden in
that thread.
Example:
from typedjsonrpc.server import current_request
@registry.method(returns=list)
def get_headers():
return list(current_request.headers)
API Reference¶
Errors¶
Error classes for typedjsonrpc.
-
exception
typedjsonrpc.errors.
Error
(data=None)[source]¶ Base class for all errors.
New in version 0.1.0.
-
exception
typedjsonrpc.errors.
InternalError
(data=None)[source]¶ Internal JSON-RPC error.
New in version 0.1.0.
-
static
from_error
(exc_info, json_encoder, debug_url=None)[source]¶ Wraps another Exception in an InternalError.
Parameters: exc_info ((type, object, traceback)) – The exception info for the wrapped exception Return type: InternalError New in version 0.1.0.
Changed in version 0.2.0: Stringifies non-JSON-serializable objects
-
static
-
exception
typedjsonrpc.errors.
InvalidParamsError
(data=None)[source]¶ Invalid method parameter(s).
New in version 0.1.0.
-
exception
typedjsonrpc.errors.
InvalidRequestError
(data=None)[source]¶ The JSON sent is not a valid request object.
New in version 0.1.0.
-
exception
typedjsonrpc.errors.
InvalidReturnTypeError
(data=None)[source]¶ Return type does not match expected type.
New in version 0.1.0.
-
exception
typedjsonrpc.errors.
MethodNotFoundError
(data=None)[source]¶ The method does not exist.
New in version 0.1.0.
Method Info¶
Data structures for wrapping methods and information about them.
-
class
typedjsonrpc.method_info.
MethodInfo
[source]¶ An object wrapping a method and information about it.
Attribute name: Name of the function Attribute method: The function being described Attribute signature: A description of the types this method takes as parameters and returns -
params
¶ The parameters for this method in a JSON-compatible format
Return type: list[dict[str, str]]
-
returns
¶ The return type for this method in a JSON-compatible format.
This handles the special case of
None
which allowstype(None)
also.Return type: str | None
-
-
class
typedjsonrpc.method_info.
MethodSignature
[source]¶ Represents the types which a function takes as input and output.
Attribute parameter_types: A list of tuples mapping strings to type with a specified order Attribute return_type: The type which the function returns -
static
create
(parameter_names, parameter_types, return_type)[source]¶ Returns a signature object ensuring order of parameter names and types.
Parameters: - parameter_names (list[str]) – A list of ordered parameter names
- parameter_types (dict[str, type]) – A dictionary of parameter names to types
- return_type (type) – The type the function returns
Return type:
-
static
Parameter Checker¶
Logic for checking parameter declarations and parameter types.
-
typedjsonrpc.parameter_checker.
check_return_type
(value, expected_type)[source]¶ Checks that the given return value has the correct type.
Parameters:
-
typedjsonrpc.parameter_checker.
check_type_declaration
(parameter_names, parameter_types)[source]¶ Checks that exactly the given parameter names have declared types.
Parameters: - parameter_names (list[str]) – The names of the parameters in the method declaration
- parameter_types (dict[str, type]) – Parameter type by name
-
typedjsonrpc.parameter_checker.
check_types
(parameters, parameter_types)[source]¶ Checks that the given parameters have the correct types.
Parameters: - parameters (dict[str, object]) – List of (name, value) pairs of the given parameters
- parameter_types (dict[str, type]) – Parameter type by name.
-
typedjsonrpc.parameter_checker.
validate_params_match
(method, parameters)[source]¶ Validates that the given parameters are exactly the method’s declared parameters.
Parameters: - method (function) – The method to be called
- parameters (dict[str, object] | list[object]) – The parameters to use in the call
Registry¶
Logic for storing and calling jsonrpc methods.
-
class
typedjsonrpc.registry.
Registry
(debug=False)[source]¶ The registry for storing and calling jsonrpc methods.
Attribute debug: Debug option which enables recording of tracebacks Attribute tracebacks: Tracebacks for debugging New in version 0.1.0.
-
__init__
(debug=False)[source]¶ Parameters: debug (bool) – If True, the registry records tracebacks for debugging purposes
-
describe
()[source]¶ Returns a description of all the methods in the registry.
Returns: Description Return type: dict[str, object] New in version 0.1.0.
-
dispatch
(request)[source]¶ Takes a request and dispatches its data to a jsonrpc method.
Parameters: request (werkzeug.wrappers.Request) – a werkzeug request with json data Returns: json output of the corresponding method Return type: str New in version 0.1.0.
-
json_decoder
= <json.decoder.JSONDecoder object>¶ The JSON decoder to use. Defaults to
json.JSONDecoder
New in version 0.1.0.
Changed in version 0.2.0: Changed from class to instance
-
json_encoder
= <json.encoder.JSONEncoder object>¶ The JSON encoder to use. Defaults to
json.JSONEncoder
New in version 0.1.0.
Changed in version 0.2.0: Changed from class to instance
-
method
(returns, **parameter_types)[source]¶ Syntactic sugar for registering a method
Example:
>>> registry = Registry() >>> @registry.method(returns=int, x=int, y=int) ... def add(x, y): ... return x + y
Parameters: - returns (type) – The method’s return type
- parameter_types (dict[str, type]) – The types of the method’s parameters
New in version 0.1.0.
-
register
(name, method, method_signature=None)[source]¶ Registers a method with a given name and signature.
Parameters: - name (str) – The name used to register the method
- method (function) – The method to register
- method_signature (MethodSignature | None) – The method signature for the given function
New in version 0.1.0.
-
Server¶
Contains the Werkzeug server for debugging and WSGI compatibility.
-
class
typedjsonrpc.server.
Server
(registry, endpoint='/api')[source]¶ A basic WSGI-compatible server for typedjsonrpc endpoints.
Attribute registry: The registry for this server New in version 0.1.0.
-
__init__
(registry, endpoint='/api')[source]¶ Parameters: - registry (typedjsonrpc.registry.Registry) – The JSON-RPC registry to use
- endpoint (str) – The endpoint to publish JSON-RPC endpoints. Default “/api”.
-
register_before_first_request
(func)[source]¶ Registers a function to be called once before the first served request.
Parameters: func (() -> object) – Function called New in version 0.1.0.
-
run
(host, port, **options)[source]¶ For debugging purposes, you can run this as a standalone server.
Warning
Security vulnerability
This uses
DebuggedJsonRpcApplication
to assist debugging. If you want to use this in production, you should runServer
as a standard WSGI app with uWSGI or another similar WSGI server.New in version 0.1.0.
-
-
class
typedjsonrpc.server.
DebuggedJsonRpcApplication
(app, **kwargs)[source]¶ A JSON-RPC-specific debugged application.
This differs from DebuggedApplication since the normal debugger assumes you are hitting the endpoint from a web browser.
A returned response will be JSON of the form:
{"traceback_id": <id>}
which you can use to hit the endpointhttp://<host>:<port>/debug/<traceback_id>
.New in version 0.1.0.
Warning
Security vulnerability
This should never be used in production because users have arbitrary shell access in debug mode.
-
__init__
(app, **kwargs)[source]¶ Parameters: - app (typedjsonrpc.server.Server) – The wsgi application to be debugged
- kwargs – The arguments to pass to the DebuggedApplication
-
debug_application
(environ, start_response)[source]¶ Run the application and preserve the traceback frames.
Parameters: - environ (dict[str, object]) – The environment which is passed into the wsgi application
- start_response ((str, list[(str, str)]) -> None) – The start_response function of the wsgi application
Return type: generator[str]
New in version 0.1.0.
-
handle_debug
(environ, start_response, traceback_id)[source]¶ Handles the debug endpoint for inspecting previous errors.
Parameters: - environ (dict[str, object]) – The environment which is passed into the wsgi application
- start_response ((str, list[(str, str)]) -> NoneType) – The start_response function of the wsgi application
- traceback_id (int) – The id of the traceback to inspect
New in version 0.1.0.
-
-
typedjsonrpc.server.
current_request
= <LocalProxy unbound>¶ A thread-local which stores the current request object when dispatching requests for
Server
.Stores a
werkzeug.wrappers.Request
.New in version 0.2.0.
Release Notes¶
0.2.0¶
This is a small update from the last release based on usage.
Features¶
- Added ability to access the current request in method call
- Allowed more flexibility in JSON serialization
Bugfixes¶
- Exceptions which are not JSON-serializable are now converted to strings using
repr()
rather than failing serialization
Backwards compatibility breaks¶
typedjsonrpc.registry.Registry.json_encoder
andtypedjsonrpc.registry.Registry.json_decoder
are now instances rather than class objects
0.1.0¶
Initial Release