.. -*- coding: utf-8 -*- ================================== JSON-RPC 2.0 Extension: Transports ================================== :Status: **proposal/draft** :Date: 2013-03-18 :Author: Roland Koebler .. contents:: **Table of Contents** :backlinks: none .. sectnum:: ----- Overview ======== JSON-RPC does not depend on any specific transport. Any transport should be possible. Nevertheless, this document lists some recommendations how to use JSON-RPC over some commonly-used transports. Sockets (Unix Domain Sockets or TCP/IP Sockets) =============================================== When using TCP or Unix Domain Sockets (or any other transport) without some high-level-protocol, you have to detect when a Request/Response is complete. Here, three ways are presented: - shutdown/close connection - netstrings - streaming JSON-decoder/splitter JSON-RPC over TCP / Unix domain sockets --------------------------------------- Use a new connection for every Request/Response. The client MUST shutdown the writing (``SHUT_WR``) to signal the end of the Request. The server MUST close the connection to signal the end of the Response. This is simple, straight-forward and robust. But it may be slow, since every Request needs a new connection. Client-side: 1. open a socket, connect 2. send Request, shutdown socket-writing 3. receive Response (=receive until close/shutdown) 4. close socket Server-side: 0. open socket, bind, listen 1. accept a connection 2. receive Request (=receive until shutdown) 3. send Response 4. close connection 5. goto 1 JSON-RPC over Netstrings ------------------------ :See: - http://cr.yp.to/proto/netstrings.txt - http://en.wikipedia.org/wiki/Netstring Encode JSON-RPC objects in netstrings. Since netstrings are a self-delimiting encoding, a single connection can be used for several Requests/Responses. But note that the server may close a connection e.g. after a timeout, so always use a new connection as fallback. JSON-RPC over TCP / Unix domain sockets with a JSON-splitter ------------------------------------------------------------ It's also possible to use a single connection for several Requests/Responses without an additional encoding. Then, (a) a streaming JSON-decoder or (b) a streaming JSON-splitter is needed, which detects the end of a JSON-object/array. Streaming JSON-decoders seem to be rare, but a JSON-splitter which only detects the end of a JSON-object/array can easily be implemented:: TODO: JSON-splitter-example But note that the server may close a connection e.g. after a timeout, so always use a new connection as fallback. JSON-RPC over HTTP ================== JSON-RPC can be simply tunneled through HTTP. :SeeAlso: HTTP specification (`RFC 2616`_) .. _RFC 2616: http://www.ietf.org/rfc/rfc2616.txt POST Request ------------ A HTTP POST request message MUST specify the following headers: - ``Content-Type``: SHOULD be ``application/json`` or ``application/json-rpc`` - ``Content-Length``: MUST contain the correct `length`_ according to the HTTP-specification. - ``Accept``: SHOULD be the same as ``Content-Type``. .. _length: http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4 .. TODO: Content-Type: application/json application/json-rpc application/jsonrequest Accept: necessary/useful? encoding? Of course, additional HTTP-features and -headers (e.g. Authorization) can be used. The Request itself is carried in the body of the HTTP message. **Example**:: POST /myservice HTTP/1.1 Host: rpc.example.com Content-Type: application/json Content-Length: ... Accept: application/json { "jsonrpc": "2.0", "method": "sum", "params": { "b": 34, "c": 56, "a": 12 }, "id": 123 } GET Request ----------- HTTP GET is *not recommended* for JSON-RPC, since it requries to encode the JSON-RPC-Request in the URL, and encoding nested data-structures in URLs can be problematic and results in (a) hardly-readable URLs and (b) an unusual GET-style. Nevertheless, the following defines how it can be done. But note that: - Often, it's better to use HTTP POST. - Only procedures that are considered safe and idempotent MAY be invoked using HTTP GET (according to `HTTP Section 9.1, Safe and Idempotent Methods`_). - Some old clients and proxies have issues wth URI lengths over 255 bytes. - URL-encoding may not work for all characters; especially non-ISO-8859-1-characters may be problematic. - It may be better to write a small wrapper which accepts a "normal" HTTP GET request (with flat parameters), decides if a JSON-RPC-service should be called and then converts it to JSON-RPC-request-syntax. It could additionally mangle the JSON-RPC-response before returning the result via HTTP to get a more REST-style interface. A HTTP GET request message uses the JSON-RPC-members as query-fields in the URL, and the values SHOULD be `URL-encoded`_. The ``id`` field always has to be considered as string. .. _URL-encoded: http://en.wikipedia.org./wiki/URL-encoding **Example**:: {"jsonrpc": "2.0", "method": "sum", "params": [3, 4], "id": "1"} -> http://rpc.example.com/myservice?jsonrpc=2.0&method=sum¶ms=%5B3%2C4%5D&id=1 {"jsonrpc": "2.0", "method": "sum", "params": {"a": 3, "b": 4}, "id": "2"} -> http://rpc.example.com/myservice?jsonrpc=2.0&method=sum¶ms=%7B%27a%27%3A+3%2C+%27b%27%3A+4%7D&id=2 .. _HTTP Section 9.1, Safe and Idempotent Methods: http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1 Response -------- The HTTP return message MUST specify the following headers: - ``Content-Type``: SHOULD be ``application/json`` or ``application/json-rpc`` - ``Content-Length``: MUST contain the correct `length`_ according to the HTTP-specification. The status code MUST be 200, except for HTTP reasons/errors. For Notifications, 204 is also allowed. The Response (both on success and error) is carried in the HTTP body. **Example on Success**:: HTTP/1.1 200 OK Connection: close Content-Length: ... Content-Type: application/json Date: Sat, 08 Jul 2006 12:04:08 GMT { "jsonrpc": "2.0", "result": 102, "id": 5 } **Example on Error**:: HTTP/1.1 200 OK Connection: close Content-Length: ... Content-Type: application/json Date: Sat, 08 Jul 2006 12:04:08 GMT { "jsonrpc": "2.0", "error": { "code": -32600, "message": "Invalid Request.", "data": "'method' is missing" }, "id": 6 } }