jsonrpc2
This package is a kit of pure Dart utility classes and methods for JSON-RPC clients and servers in Dart. You just provide the actual communications protocols. Instructions, examples, and tests are provided.
JSON-RPC is a JSON unicode grammar for calling methods on a remote server and getting responses back. The specification is at https://jsonrpc.org.
Usage:
JSON-RPC is divided into client and server responsibilities. This package does the fussy part of the JSON-RPC 2.0 specification, with failover to 1.0 for the server.
Client
Like the specification, the client implementation does not specify transport details for the client. One needs to create a class extended from ServerProxyBase to actually send method requests and receive responses. Look in Examples for common use cases, or see below for step-by-step instructions.
Once instantiated, a client proxy may call methods on the server using the call method of the proxy, and receive a response. It is a client responsibility to match the server's API.
Future<dynamic> call(String method, [dynamic params])
-
proxy.call('method_a') // no args
-
proxy.call('method_b',
arg1
) // one arg, general case -
proxy.call('method_c', arg1) // one arg, arg is neither [] nor {}
-
proxy.call('method_d',
arg1, arg2, arg3
) // more than one arg -
proxy.call('method_e', [
item1, item2, item3, item4
]) // one arg, arg is [] -
proxy.call('method_f',
{'a': 'hello', 'b': 'world'}
) // one arg, arg is {} -
proxy.call('method_g', {'name_a':value_a,'name_b':value_b}) // named args
Creating a Client (ServerProxy) Class
- Import the client library.
import 'package:jsonrpc2/jsonrpc2.dart';
import 'package:rpc_exceptions/rpc_exceptions.dart';
- Create a server proxy class, extended from ServerProxyBase, initialized with a server resource. resource may be used in the transmit method.
class MyServerProxy extends ServerProxyBase {
/// constructor. extend this, if you want, then superize properly
MyServerProxy(resource) // resource can be anything
: super(resource);
}
- In your server proxy class override the transmit method, which sends a String to the remote JSON-RPC server and returns the returned string. You may use the server resource identified earlier.
/// Return a Future with the JSON-RPC response. Use a real transport,
/// like package:http instead of imaginary ExampleTransport.
@override
Future<String> transmit(String package) async {
// for example, create a transport using a string resource name.
var transport = ExampleTransport(resource);
// send the package using the transport, and await response
var response = await transport.send(package);
// return the String response for further processing
return response;
}
- Use an instance of your server proxy to call a method on that endpoint, and do something with the result.
/// get the item in the server's list that follows this item
MyViewItem nextItem (String lastItemId) async {
var remoteSite = MyServerProxy('https://example.org/');
var item = await remoteSite.call('nextItem', lastItemId);
// Or, if you have mirrored the server API in your proxy,
// var nextItem = await remoteSite.nextItem(lastItemId); // nice!
return MyViewItem.fromJson(item);
}
Example JSON-RPC Client using http.dart from pub.dev: http_client
Server Basics
The server library decodes JSON-RPC request packages and allows association of the JSON-RPC request with an object that calls the remote methods, and returns a result. Network and transport issues are outside the scope of this implementation. That said, this is designed to be fairly easy with the transport or framework you are using. It's just a method that uses a dispatcher. In a server implementation, make an endpoint for a particular Dispatcher, and use these utilities to decode the request and package the result.
This server implementation uses a Dispatcher concept. Essentially, a dispatcher is an instantiated class that contains the remote methods to be called at an endpoint. The server accepts a call request, deconstructs the JSON, then creates or associates a dispatcher to call the method on that instance, with the requested parameters. The returned value (or exception) is assembled in JSON as a response and sent back to the client.
- Import the server library
import 'package:jsonrpc2/jsonrpc2.dart';
- Create a class implementing the service methods at an endpoint. Just about any class with methods will do. example api class, and import it, if it is in a different file.
import 'rpc_methods.dart';
- make a method for your listener that accepts JSON-RPC strings from the client. This string may be, for example, the body of a HTTP POST. Within this method, use this library's jsonRpc method to associate the string with the Dispatcher, which performs the method. The jsonRpc method will ultimately produce a string, which should be sent back to the client as a response.
The jsonRpc method has the following signature.
Future<String> jsonRpc(String request, Dispatcher dispatcher)
-- request is a JSON-RPC request string, the request from the client.
-- a dispatcher meets the Dispatcher interface. You will want to use one of the following:
These two implementations work equivalently. Mirror_dispatcher is easier to use, but it uses dart:mirrors, which cannot be used inside a flutter app. There may be other trade-offs.