| A library that implements the [JSON-RPC 2.0 spec][spec]. |
| |
| [spec]: http://www.jsonrpc.org/specification |
| |
| ## Server |
| |
| A JSON-RPC 2.0 server exposes a set of methods that can be called by clients. |
| These methods can be registered using `Server.registerMethod`: |
| |
| ```dart |
| import "package:json_rpc_2/json_rpc_2.dart" as json_rpc; |
| import "package:stream_channel/stream_channel.dart"; |
| |
| main() async { |
| var socket = await WebSocket.connect('ws://localhost:4321'); |
| var server = new json_rpc.Server(new StreamChannel(socket, socket)); |
| |
| // Any string may be used as a method name. JSON-RPC 2.0 methods are |
| // case-sensitive. |
| var i = 0; |
| server.registerMethod("count", () { |
| // Just return the value to be sent as a response to the client. This can |
| // be anything JSON-serializable, or a Future that completes to something |
| // JSON-serializable. |
| return i++; |
| }); |
| |
| // Methods can take parameters. They're presented as a [Parameters] object |
| // which makes it easy to validate that the expected parameters exist. |
| server.registerMethod("echo", (params) { |
| // If the request doesn't have a "message" parameter, this will |
| // automatically send a response notifying the client that the request |
| // was invalid. |
| return params.getNamed("message"); |
| }); |
| |
| // [Parameters] has methods for verifying argument types. |
| server.registerMethod("subtract", (params) { |
| // If "minuend" or "subtrahend" aren't numbers, this will reject the |
| // request. |
| return params.getNum("minuend") - params.getNum("subtrahend"); |
| }); |
| |
| // [Parameters] also supports optional arguments. |
| server.registerMethod("sort", (params) { |
| var list = params.getList("list"); |
| list.sort(); |
| if (params.getBool("descending", orElse: () => false)) { |
| return params.list.reversed; |
| } else { |
| return params.list; |
| } |
| }); |
| |
| // A method can send an error response by throwing a |
| // `json_rpc.RpcException`. Any positive number may be used as an |
| // application- defined error code. |
| const DIVIDE_BY_ZERO = 1; |
| server.registerMethod("divide", (params) { |
| var divisor = params.getNum("divisor"); |
| if (divisor == 0) { |
| throw new json_rpc.RpcException( |
| DIVIDE_BY_ZERO, "Cannot divide by zero."); |
| } |
| |
| return params.getNum("dividend") / divisor; |
| }); |
| |
| // To give you time to register all your methods, the server won't actually |
| // start listening for requests until you call `listen`. |
| server.listen(); |
| } |
| ``` |
| |
| ## Client |
| |
| A JSON-RPC 2.0 client calls methods on a server and handles the server's |
| responses to those method calls. These methods can be called using |
| `Client.sendRequest`: |
| |
| ```dart |
| import "package:json_rpc_2/json_rpc_2.dart" as json_rpc; |
| import "package:stream_channel/stream_channel.dart"; |
| |
| main() async { |
| var socket = await WebSocket.connect('ws://localhost:4321'); |
| var client = new json_rpc.Client(new StreamChannel(socket, socket)); |
| |
| // This calls the "count" method on the server. A Future is returned that |
| // will complete to the value contained in the server's response. |
| client.sendRequest("count").then((result) => print("Count is $result.")); |
| |
| // Parameters are passed as a simple Map or, for positional parameters, an |
| // Iterable. Make sure they're JSON-serializable! |
| client.sendRequest("echo", {"message": "hello"}) |
| .then((echo) => print('Echo says "$echo"!')); |
| |
| // A notification is a way to call a method that tells the server that no |
| // result is expected. Its return type is `void`; even if it causes an |
| // error, you won't hear back. |
| client.sendNotification("count"); |
| |
| // If the server sends an error response, the returned Future will complete |
| // with an RpcException. You can catch this error and inspect its error |
| // code, message, and any data that the server sent along with it. |
| client.sendRequest("divide", {"dividend": 2, "divisor": 0}) |
| .catchError((error) { |
| print("RPC error ${error.code}: ${error.message}"); |
| }); |
| |
| // The client won't subscribe to the input stream until you call `listen`. |
| client.listen(); |
| } |
| ``` |
| |
| ## Peer |
| |
| Although JSON-RPC 2.0 only explicitly describes clients and servers, it also |
| mentions that two-way communication can be supported by making each endpoint |
| both a client and a server. This package supports this directly using the `Peer` |
| class, which implements both `Client` and `Server`. It supports the same methods |
| as those classes, and automatically makes sure that every message from the other |
| endpoint is routed and handled correctly. |