Chromium Code Reviews| Index: README.md |
| diff --git a/README.md b/README.md |
| index 3d09d0f394a5878d9f914345cb0f8862a69750ea..8bfbec0cac4a09525f8ec428e08dab568e8844d4 100644 |
| --- a/README.md |
| +++ b/README.md |
| @@ -10,89 +10,109 @@ 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++; |
| -}); |
| +WebSocket.connect('ws://localhost:4321').then((socket) { |
|
Bob Nystrom
2015/02/05 00:32:24
Would it be premature to use await here? :)
Also,
nweiz
2015/02/05 01:02:48
Yes :(
|
| + // 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++; |
| + }); |
| -// 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"); |
| -}); |
| + // Methods can take parameters. They're presented as a [Parameters] object which |
|
Bob Nystrom
2015/02/05 00:32:24
Some long lines.
nweiz
2015/02/05 01:02:48
Done.
|
| + // 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] 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; |
| - } |
| -}); |
| + // [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."); |
| - } |
| + // 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; |
| + }); |
| - 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`. |
| + return server.listen(); |
| }); |
| ``` |
| -Once you've registered your methods, you can handle requests with |
| -`Server.parseRequest`: |
| +## 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:io'; |
| +import "package:json_rpc_2/json_rpc_2.dart" as json_rpc; |
| WebSocket.connect('ws://localhost:4321').then((socket) { |
| - socket.listen((message) { |
| - server.parseRequest(message).then((response) { |
| - if (response != null) socket.add(response); |
| - }); |
| + // 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) { |
|
Bob Nystrom
2015/02/05 00:32:25
Long.
nweiz
2015/02/05 01:02:48
Done.
|
| + print("RPC error ${error.code}: ${error.message}"); |
| }); |
| -}); |
| -``` |
| - |
| -If you're communicating with objects that haven't been serialized to a string, |
| -you can also call `Server.handleRequest` directly: |
| -```dart |
| -import 'dart:isolate'; |
| - |
| -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); |
| - }); |
| - }); |
| -}) |
| + // 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 same methods as |
|
Bob Nystrom
2015/02/05 00:32:25
"same" -> "the same".
nweiz
2015/02/05 01:02:48
Done.
|
| +those classes, and automatically makes sure that every message from the other |
| +endpoint is routed and handled correctly. |