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