Skip to content

Migration

From 5.x to 6.0

Code that registers methods with @method, returns Success(...), Error(...) or a plain value, and calls dispatch or async_dispatch keeps working. A test in the repository pins that. The rest of this section lists everything that changed, so you can check your own code against it.

Python 3.11 or later

6.0 needs Python 3.11 or later. 3.8, 3.9 and 3.10 have reached end of life. On an older Python, pip install jsonrpcserver keeps installing 5.x.

Results and responses are dataclasses

5.x built results and responses on the oslash library's Right and Left. 6.0 has no dependencies, and they're plain frozen dataclasses:

5.x 6.0
Success(x) is a Right holding a SuccessResult Success(x) is a SuccessResult
Error(...) is a Left holding an ErrorResult Error(...) is an ErrorResult
isinstance(response, Left) isinstance(response, ErrorResponse)
response._value.result response.result
response._error.code response.code
from oslash.either import Left, Right not needed
a mypy setting for oslash not needed

Code that reads responses from dispatch_to_response, or that a post_process function receives, needs the change in the table. Code that only uses dispatch, async_dispatch or dispatch_to_serializable doesn't.

InvalidResultError, validate_result and log_invalid_result are gone from jsonrpcserver.dispatcher. Without the wrappers there's no invalid Result left: whatever a method returns is its result.

Requests are checked without jsonschema

The default validator checks the same rules as before, without the jsonschema library. It raises jsonrpcserver.validator.InvalidRequestError, and the client gets the same -32600 response. jsonrpcserver/request-schema.json is gone. If you imported it, copy it from 5.x. Dispatching is about four times faster for a small method.

Safer defaults

5.x 6.0 To get the 5.x behaviour
Batch size no limit 100 requests max_batch_size=None
NaN, Infinity, 1e400 in a request accepted -32700 Parse error deserializer=json.loads
Error or JsonRpcError with a non-integer code or a non-string message UserWarning, sent as given TypeError none: fix the code or message
@method name starting with rpc. UserWarning, added ValueError none: rename the method
serve() with no host every network interface localhost only serve("", port)

dispatch_to_response used json.loads as its default deserializer, unlike the other dispatch functions. It uses the same default as them now.

Removed names

Removed Use
jsonrpcserver.response.serialize_error to_error_dict
jsonrpcserver.response.serialize_success to_success_dict
jsonrpcserver.response.to_serializable_one, jsonrpcserver.main.to_serializable_one to_dict
jsonrpcserver.response.ResponseType Response

All four gave a DeprecationWarning from 5.0.10.

New

max_concurrency on the async dispatch functions limits how many requests of a batch run at once. See Async.

From 4.x to 5.x

Version 5 changed how methods report their result. Most other code needs only small changes.

Old methods fail with no details before 5.1.0

In 4.x a method returned its result directly. In 5.0.x it must return Success(result). From 5.1.0 a plain return value works again, and becomes Success(value). On 5.0.x, a 4.x method such as

@method
def ping():
    return "pong"

still runs, but the client gets a -32603 "Internal error". Up to 5.0.9, its data says "The method did not return a valid Result". From 5.0.10 the client gets no details, and the log says what's wrong:

Method 'ping' returned 'pong', which is not a Result, so the client got an Internal error. Return Success(value) or Error(code, message). ...

That's the 5.0.10 message. Upgrading to 5.1.0 fixes these methods without a code change.

If you don't see that line, configure logging (see Errors and logging). Then search your code for return statements in methods. mypy and pyright catch them too, once methods are annotated -> Result (see Typing).

A method, before and after

4.x:

# jsonrpcserver 4.x. This doesn't work on 5.x.
from jsonrpcserver import dispatch, method
from jsonrpcserver.exceptions import ApiError, InvalidParamsError


@method
def divide(a, b):
    if not isinstance(b, (int, float)):
        raise InvalidParamsError("b must be a number")
    if b == 0:
        raise ApiError("Can't divide by zero", code=1)
    return a / b


response = dispatch(request_body)
if response.wanted:
    send(str(response), status=response.http_status)

5.x:

from jsonrpcserver import Error, InvalidParams, Result, Success, dispatch, method


@method
def divide(a: float, b: float) -> Result:
    if not isinstance(b, (int, float)):
        return InvalidParams("b must be a number")
    if b == 0:
        return Error(1, "Can't divide by zero")
    return Success(a / b)


response = dispatch('{"jsonrpc": "2.0", "method": "divide", "params": [1, 0], "id": 1}')
print(response, 200 if response else 204)
Output
{"jsonrpc": "2.0", "error": {"code": 1, "message": "Can't divide by zero"}, "id": 1} 200

What changed

4.x 5.x
return value return Success(value). From 5.1.0 return value works too
raise ApiError(message, code=1, data=...) return Error(code, message, data), or raise JsonRpcError(code, message, data). Note the order: code first.
raise InvalidParamsError(...) return InvalidParams(data)
raise MethodNotFoundError there's no equivalent. jsonrpcserver sends "Method not found" itself
dispatch returns a Response object dispatch returns a string. dispatch_to_serializable gives a dict
str(response) response is already the string
response.wanted if response:, since a notification gives ""
response.http_status 200 if response else 204. Errors are sent with 200 too
methods = Methods(ping, add), methods.add(...) a plain dict, {"ping": ping, "add": add}, or @method
dispatch(..., serialize=..., deserialize=...) serializer= and deserializer=
convert_camel_case=True removed. Name your methods and parameters as clients call them
basic_logging=True, trim_log_values=True removed. Configure the jsonrpcserver logger yourself
a .jsonrpcserverrc config file removed. Pass options to dispatch
debug=True removed in 5.0.0, so 5.0.0 to 5.0.9 always send exception messages to the client. Back in 5.0.10, where it works as in 4.x: off by default

Code written for 4.x that 5.x can't run gives clear errors in most cases. The removed keywords raise TypeError, and response.wanted raises AttributeError: 'str' object has no attribute 'wanted'. The plain return value above is the one that fails quietly before 5.1.0, and str(response) still works but is no longer needed.

The 4.x documentation is no longer online. The changelog lists every 4.x change.

From 5.0.9 to 5.0.10

Most code needs no change. These are the differences you might notice.

Exception messages are no longer sent. A method that raises an exception it doesn't catch gives a -32603 "Internal error" with no data. Clients that read error.data for those errors get nothing now. The exception is logged. Pass debug=True in development to get the message back in the response. See Security.

Custom validators see one request at a time. In a batch, the validator is called once for each request, with just that request. In 5.0.9 it was called once with the whole list. A validator that enforced a rule about the whole batch, such as a size limit, silently stops doing it. Use max_batch_size instead. See Validation.

Batches are handled per request. A batch that mixes valid and invalid requests used to get one "Invalid request" for the whole batch. Now each invalid request gets its own error, and the valid ones run. See Notifications and batches.

NaN and Infinity give an error. A result that contains NaN, Infinity or -Infinity now gives an Internal error, because they aren't valid JSON. To send them anyway, pass serializer=json.dumps.

A result that can't be serialized gives an error. For example a datetime. In 5.0.9 dispatch raised TypeError. Now that response becomes an Internal error, the error is logged, and the rest of a batch is sent.

New warnings. Error and JsonRpcError warn when the code isn't an integer or the message isn't a string, and @method warns about names that start with rpc.. The responses are the same as before. If your tests turn warnings into errors, fix the code or the names. See Errors and logging.

Deprecated names. In jsonrpcserver.response, serialize_error, serialize_success and to_serializable_one give a DeprecationWarning. Use to_error_dict, to_success_dict and to_dict. ResponseType is kept, but use Response. They will be removed in 6.0.

New loggers and log lines. A serializer failure is logged on jsonrpcserver.main, and serve() logs where it's listening. A method that returns a plain value is logged with a hint instead of a traceback. See Errors and logging.

Plain methods work with async_dispatch. In 5.0.9 they gave an Internal error.

serve() sends 204 for a notification, instead of 200 with an empty body, and answers bad requests instead of dropping the connection.

New features you can use: max_batch_size and debug on every dispatch function, jsonrpcserver.__version__, and type checking that sees through @method (see Typing).

Python 3.8 or later. 5.0.10's package metadata says so, so older Pythons keep installing 5.0.9.