OLD | NEW |
---|---|
1 A library that implements the [JSON-RPC 2.0 spec][spec]. | 1 A library that implements the [JSON-RPC 2.0 spec][spec]. |
2 | 2 |
3 [spec]: http://www.jsonrpc.org/specification | 3 [spec]: http://www.jsonrpc.org/specification |
4 | 4 |
5 ## Server | 5 ## Server |
6 | 6 |
7 A JSON-RPC 2.0 server exposes a set of methods that can be called by clients. | 7 A JSON-RPC 2.0 server exposes a set of methods that can be called by clients. |
8 These methods can be registered using `Server.registerMethod`: | 8 These methods can be registered using `Server.registerMethod`: |
9 | 9 |
10 ```dart | 10 ```dart |
11 import "package:json_rpc_2/json_rpc_2.dart" as json_rpc; | 11 import "package:json_rpc_2/json_rpc_2.dart" as json_rpc; |
12 | 12 |
13 var server = new json_rpc.Server(); | 13 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 :(
| |
14 // You can start the server with a Stream for requests and a StreamSink for | |
15 // responses, or with an object that's both, like a WebSocket. | |
16 var server = new json_rpc.Server(socket); | |
14 | 17 |
15 // Any string may be used as a method name. JSON-RPC 2.0 methods are | 18 // Any string may be used as a method name. JSON-RPC 2.0 methods are |
16 // case-sensitive. | 19 // case-sensitive. |
17 var i = 0; | 20 var i = 0; |
18 server.registerMethod("count", () { | 21 server.registerMethod("count", () { |
19 // Just return the value to be sent as a response to the client. This can be | 22 // Just return the value to be sent as a response to the client. This can be |
20 // anything JSON-serializable, or a Future that completes to something | 23 // anything JSON-serializable, or a Future that completes to something |
21 // JSON-serializable. | 24 // JSON-serializable. |
22 return i++; | 25 return i++; |
26 }); | |
27 | |
28 // Methods can take parameters. They're presented as a [Parameters] object whi ch | |
Bob Nystrom
2015/02/05 00:32:24
Some long lines.
nweiz
2015/02/05 01:02:48
Done.
| |
29 // makes it easy to validate that the expected parameters exist. | |
30 server.registerMethod("echo", (params) { | |
31 // If the request doesn't have a "message" parameter, this will automaticall y | |
32 // send a response notifying the client that the request was invalid. | |
33 return params.getNamed("message"); | |
34 }); | |
35 | |
36 // [Parameters] has methods for verifying argument types. | |
37 server.registerMethod("subtract", (params) { | |
38 // If "minuend" or "subtrahend" aren't numbers, this will reject the request . | |
39 return params.getNum("minuend") - params.getNum("subtrahend"); | |
40 }); | |
41 | |
42 // [Parameters] also supports optional arguments. | |
43 server.registerMethod("sort", (params) { | |
44 var list = params.getList("list"); | |
45 list.sort(); | |
46 if (params.getBool("descending", orElse: () => false)) { | |
47 return params.list.reversed; | |
48 } else { | |
49 return params.list; | |
50 } | |
51 }); | |
52 | |
53 // A method can send an error response by throwing a `json_rpc.RpcException`. | |
54 // Any positive number may be used as an application-defined error code. | |
55 const DIVIDE_BY_ZERO = 1; | |
56 server.registerMethod("divide", (params) { | |
57 var divisor = params.getNum("divisor"); | |
58 if (divisor == 0) { | |
59 throw new json_rpc.RpcException(DIVIDE_BY_ZERO, "Cannot divide by zero."); | |
60 } | |
61 | |
62 return params.getNum("dividend") / divisor; | |
63 }); | |
64 | |
65 // To give you time to register all your methods, the server won't actually | |
66 // start listening for requests until you call `listen`. | |
67 return server.listen(); | |
23 }); | 68 }); |
24 | |
25 // Methods can take parameters. They're presented as a [Parameters] object which | |
26 // makes it easy to validate that the expected parameters exist. | |
27 server.registerMethod("echo", (params) { | |
28 // If the request doesn't have a "message" parameter, this will automatically | |
29 // send a response notifying the client that the request was invalid. | |
30 return params.getNamed("message"); | |
31 }); | |
32 | |
33 // [Parameters] has methods for verifying argument types. | |
34 server.registerMethod("subtract", (params) { | |
35 // If "minuend" or "subtrahend" aren't numbers, this will reject the request. | |
36 return params.getNum("minuend") - params.getNum("subtrahend"); | |
37 }); | |
38 | |
39 // [Parameters] also supports optional arguments. | |
40 server.registerMethod("sort", (params) { | |
41 var list = params.getList("list"); | |
42 list.sort(); | |
43 if (params.getBool("descending", orElse: () => false)) { | |
44 return params.list.reversed; | |
45 } else { | |
46 return params.list; | |
47 } | |
48 }); | |
49 | |
50 // A method can send an error response by throwing a `json_rpc.RpcException`. | |
51 // Any positive number may be used as an application-defined error code. | |
52 const DIVIDE_BY_ZERO = 1; | |
53 server.registerMethod("divide", (params) { | |
54 var divisor = params.getNum("divisor"); | |
55 if (divisor == 0) { | |
56 throw new json_rpc.RpcException(DIVIDE_BY_ZERO, "Cannot divide by zero."); | |
57 } | |
58 | |
59 return params.getNum("dividend") / divisor; | |
60 }); | |
61 ``` | |
62 | |
63 Once you've registered your methods, you can handle requests with | |
64 `Server.parseRequest`: | |
65 | |
66 ```dart | |
67 import 'dart:io'; | |
68 | |
69 WebSocket.connect('ws://localhost:4321').then((socket) { | |
70 socket.listen((message) { | |
71 server.parseRequest(message).then((response) { | |
72 if (response != null) socket.add(response); | |
73 }); | |
74 }); | |
75 }); | |
76 ``` | |
77 | |
78 If you're communicating with objects that haven't been serialized to a string, | |
79 you can also call `Server.handleRequest` directly: | |
80 | |
81 ```dart | |
82 import 'dart:isolate'; | |
83 | |
84 var receive = new ReceivePort(); | |
85 Isolate.spawnUri('path/to/client.dart', [], receive.sendPort).then((_) { | |
86 receive.listen((message) { | |
87 server.handleRequest(message['request']).then((response) { | |
88 if (response != null) message['respond'].send(response); | |
89 }); | |
90 }); | |
91 }) | |
92 ``` | 69 ``` |
93 | 70 |
94 ## Client | 71 ## Client |
95 | 72 |
96 Currently this package does not contain an implementation of a JSON-RPC 2.0 | 73 A JSON-RPC 2.0 client calls methods on a server and handles the server's |
97 client. | 74 responses to those method calls. These methods can be called using |
75 `Client.sendRequest`: | |
98 | 76 |
77 ```dart | |
78 import "package:json_rpc_2/json_rpc_2.dart" as json_rpc; | |
79 | |
80 WebSocket.connect('ws://localhost:4321').then((socket) { | |
81 // Just like the server, a client takes a Stream and a StreamSink or a | |
82 // single object that's both. | |
83 var client = new json_rpc.Client(socket); | |
84 | |
85 // This calls the "count" method on the server. A Future is returned that will | |
86 // complete to the value contained in the server's response. | |
87 client.sendRequest("count").then((result) => print("Count is $result.")); | |
88 | |
89 // Parameters are passed as a simple Map or, for positional parameters, an | |
90 // Iterable. Make sure they're JSON-serializable! | |
91 client.sendRequest("echo", {"message": "hello"}) | |
92 .then((echo) => print('Echo says "$echo"!')); | |
93 | |
94 // A notification is a way to call a method that tells the server that no | |
95 // result is expected. Its return type is `void`; even if it causes an error, | |
96 // you won't hear back. | |
97 client.sendNotification("count"); | |
98 | |
99 // If the server sends an error response, the returned Future will complete | |
100 // with an RpcException. You can catch this error and inspect its error code, | |
101 // message, and any data that the server sent along with it. | |
102 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.
| |
103 print("RPC error ${error.code}: ${error.message}"); | |
104 }); | |
105 | |
106 // The client won't subscribe to the input stream until you call `listen`. | |
107 client.listen(); | |
108 }); | |
109 ``` | |
110 | |
111 ## Peer | |
112 | |
113 Although JSON-RPC 2.0 only explicitly describes clients and servers, it also | |
114 mentions that two-way communication can be supported by making each endpoint | |
115 both a client and a server. This package supports this directly using the `Peer` | |
116 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.
| |
117 those classes, and automatically makes sure that every message from the other | |
118 endpoint is routed and handled correctly. | |
OLD | NEW |