From 8bf9eca481e48aad17271105d4f933d85f3b5955 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Thu, 5 Feb 2015 16:26:17 -0800 Subject: [PATCH] Update the README to match the current API. R=rnystrom@google.com Closes #2 Review URL: https://codereview.chromium.org//899093003 --- CHANGELOG.md | 4 ++ README.md | 171 ++++++++++++++++++++++++++++++--------------------- pubspec.yaml | 2 +- 3 files changed, 105 insertions(+), 72 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1934fc0..a1bd217 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.1.1 + +* Update the README to match the current API. + ## 1.1.0 * Add a `done` getter to `Client`, `Server`, and `Peer`. diff --git a/README.md b/README.md index 3d09d0f..67afc31 100644 --- a/README.md +++ b/README.md @@ -10,89 +10,118 @@ These methods can be registered using `Server.registerMethod`: ```dart import "package:json_rpc_2/json_rpc_2.dart" as json_rpc; -var server = new json_rpc.Server(); - -// 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; -}); -``` +void main() { + WebSocket.connect('ws://localhost:4321').then((socket) { + // You can start the server with a Stream for requests and a StreamSink for + // responses, or with an object that's both, like a WebSocket. + var server = new json_rpc.Server(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++; + }); -Once you've registered your methods, you can handle requests with -`Server.parseRequest`: + // 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"); + }); -```dart -import 'dart:io'; + // [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; + } + }); -WebSocket.connect('ws://localhost:4321').then((socket) { - socket.listen((message) { - server.parseRequest(message).then((response) { - if (response != null) socket.add(response); + // 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(); }); -}); +} ``` -If you're communicating with objects that haven't been serialized to a string, -you can also call `Server.handleRequest` directly: +## 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 'dart:isolate'; +import "package:json_rpc_2/json_rpc_2.dart" as json_rpc; -var receive = new ReceivePort(); -Isolate.spawnUri('path/to/client.dart', [], receive.sendPort).then((_) { - receive.listen((message) { - server.handleRequest(message['request']).then((response) { - if (response != null) message['respond'].send(response); +void main() { + WebSocket.connect('ws://localhost:4321').then((socket) { + // Just like the server, a client takes a Stream and a StreamSink or a + // single object that's both. + var client = new json_rpc.Client(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(); }); -}) +} ``` -## Client - -Currently this package does not contain an implementation of a JSON-RPC 2.0 -client. +## 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. diff --git a/pubspec.yaml b/pubspec.yaml index abc05ab..bf5939c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: json_rpc_2 -version: 1.1.0 +version: 1.1.1 author: Dart Team description: An implementation of the JSON-RPC 2.0 spec. homepage: http://github.com/dart-lang/json_rpc_2