
json_rpc_server.pl -- JSON RPC Server
This module implements an JSON RPC server. It provides declarations that bind Prolog predicates to JSON RPC methods and a dispatch loop that acts on a bi-directional stream. This module assumes a two-directional stream and provides json_rpc_dispatch/2 that receiveds JSON messages on the input side of this stream and sends the replies through the output. This module does not implement obtaining such a stream. Obvious candidates for obtaining a stream are:
- Using standard I/O to a child process. See process_create/3.
- Using sockets. See library(socket). Using the SSL package this also provides secure sockets.
- Using the HTTP package to extablish a web socket.
This library defines json_method/1 for declaring predicates to act as a JSON method. The declaration accepts a JSON Schema specification, represented as a SWI-Prolog dict to specify the input parameters as well as the output.
json_method(+Methods)- Methods is a comma-list of JSON RPC method declarations. Each
declaration takes one of the forms below:
- Callable:Reply
- Here, Callable is a Prolog callable term whose name and number of argument match a predicate in this module. The arguments are JSON Schema types and Reply is a JSON Schema type.
- Callable
- Callable is as above, but there is no return value. This implements JSON RPC notifications, i.e., asynchronously processed messages for which we do not wait for a reply.
For example:
:- json_method subtract(#{type:number}, #{type:number}): #{type:number}. subtract(A, B, R) :- R is A-B.Methods with named arguments can be implemented using a single argument that is an object with specified properties. For example, the program below implements a depositing to a bank account. The method takes an
accountandamountparameter and returns the new balance. The json_rpc_error/2 throws a JSON RPC application error.:- json_method deposit(#{ properties: #{ account: #{type:string}, amount: #{type:number} }}): #{type:number}, deposit(Request, Reply), #{account: Account, amount: Amount} :< Request => transaction(( retract(account(Account, Old)) -> New is Old+Amount, asserta(account(Account, New)) ; json_rpc_error(2, "Account does not exist") )), Reply = New.
json_rpc_dispatch(:Stream, +Options) is det- Run the JSON RPC dispatch loop until end of file is reached on Stream.
json_rpc_dispatch_request(+Module, +Stream, +Request, +Options)- Handle a request that has been read from Stream, possibly sending a reply to Stream.
json_rpc_reply(+Stream, +Result, +Options) is det[private]
check_params(+CallParams, +ExpectedTypes, -Params, +Options) is det[private]
json_exception_to_reply(+Error, +Request, -Reply) is det[private]- Turn an exception into a JSON RPC error document if Request has an
idfield. Else it is a notification, so we simply print the message in the server.
raise_run_error(+Error)[private]- Raised an error generated while running the method. This can be an application error raised by json_rpc_error/2,3 or an arbitrary error.
json_rpc_error(+Code, +Message)
json_rpc_error(+Code, +Message, +Data)- Normally called from a method implementation to raise an application error.
Undocumented predicates
The following predicates are exported, but not or incorrectly documented.