Skip to content
This repository has been archived by the owner on Oct 28, 2024. It is now read-only.

Commit

Permalink
Fix README for style (#53)
Browse files Browse the repository at this point in the history
Add an example with content from the readme. This improves the score on
pub and lets me run the analyzer over the example.

- Remove the import prefix for the example, it is especially unwieldy
  for the `Parameters` type annotation.
- Add argument types to the callbacks to avoid implicit `dynamic` which
  makes it harder to use inside the method body.
- Change `[]` inside comments to backticks. `[]` is only used for doc
  comments.
- Drop the `getNamed` API that has not been present since the very first
  code review for this package.
- Use lower camel case for a constant.
- Use single quotes consistently. There was a mix before, this is
  especially important for imports which are idiomatically written with
  single quotes.
- Add a note about message buffering before `listen`.
- Use `WebSocketChannel.connect` for platform agnostic imports.
- Use `async/await` in the client example.
  • Loading branch information
natebosch authored Jun 1, 2020
1 parent d589e63 commit 1fa5626
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 50 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
## 2.2.1-dev

## 2.2.0

* Added `strictProtocolChecks` named parameter to `Server` and `Peer`
Expand Down
100 changes: 51 additions & 49 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,71 +8,70 @@ 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";
import "package:web_socket_channel/io.dart";
import 'package:json_rpc_2/json_rpc_2.dart';
import 'package:web_socket_channel/web_socket_channel.dart';
main() async {
var socket = IOWebSocketChannel.connect('ws://localhost:4321');
void main() {
var socket = WebSocketChannel.connect(Uri.parse('ws://localhost:4321'));
// The socket is a StreamChannel<dynamic> because it might emit binary
// List<int>s, but JSON RPC 2 only works with Strings so we assert it only
// The socket is a `StreamChannel<dynamic>` because it might emit binary
// `List<int>`, but JSON RPC 2 only works with Strings so we assert it only
// emits those by casting it.
var server = new json_rpc.Server(socket.cast<String>());
var server = Server(socket.cast<String>());
// Any string may be used as a method name. JSON-RPC 2.0 methods are
// case-sensitive.
var i = 0;
server.registerMethod("count", () {
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
// 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
server.registerMethod('echo', (Parameters 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");
return params['message'].value;
});
// [Parameters] has methods for verifying argument types.
server.registerMethod("subtract", (params) {
// `Parameters` has methods for verifying argument types.
server.registerMethod('subtract', (Parameters params) {
// If "minuend" or "subtrahend" aren't numbers, this will reject the
// request.
return params.getNum("minuend") - params.getNum("subtrahend");
return params['minuend'].asNum - params['subtrahend'].asNum;
});
// [Parameters] also supports optional arguments.
server.registerMethod("sort", (params) {
var list = params.getList("list");
server.registerMethod('sort', (Parameters params) {
var list = params['list'].asList;
list.sort();
if (params.getBool("descending", orElse: () => false)) {
return params.list.reversed;
if (params['descendint'].asBoolOr(false)) {
return list.reversed;
} else {
return params.list;
return 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");
// A method can send an error response by throwing a `RpcException`.
// Any positive number may be used as an application- defined error code.
const dividByZero = 1;
server.registerMethod('divide', (Parameters params) {
var divisor = params['divisor'].asNum;
if (divisor == 0) {
throw new json_rpc.RpcException(
DIVIDE_BY_ZERO, "Cannot divide by zero.");
throw RpcException(dividByZero, 'Cannot divide by zero.');
}
return params.getNum("dividend") / divisor;
return params['dividend'].asNum / divisor;
});
// To give you time to register all your methods, the server won't actually
// start listening for requests until you call `listen`.
// To give you time to register all your methods, the server won't start
// listening for requests until you call `listen`. Messages are buffered until
// listen is called. The returned Future won't complete until the connection
// is closed.
server.listen();
}
```
Expand All @@ -84,38 +83,41 @@ 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";
import "package:web_socket_channel/html.dart";
import 'package:json_rpc_2/json_rpc_2.dart';
import 'package:pedantic/pedantic.dart';
import 'package:web_socket_channel/web_socket_channel.dart';
main() async {
var socket = HtmlWebSocketChannel.connect('ws://localhost:4321');
var client = new json_rpc.Client(socket);
void main() async {
var socket = WebSocketChannel.connect(Uri.parse('ws://localhost:4321'));
var client = Client(socket.cast<String>());
// The client won't subscribe to the input stream until you call `listen`.
// The returned Future won't complete until the connection is closed.
unawaited(client.listen());
// 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."));
var count = await client.sendRequest('count');
print('Count is $count');
// 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"!'));
var echo = await client.sendRequest('echo', {'message': 'hello'});
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");
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();
try {
await client.sendRequest('divide', {'dividend': 2, 'divisor': 0});
} on RpcException catch (error) {
print('RPC error ${error.code}: ${error.message}');
}
}
```

Expand Down
40 changes: 40 additions & 0 deletions example/client.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:json_rpc_2/json_rpc_2.dart';
import 'package:pedantic/pedantic.dart';
import 'package:web_socket_channel/web_socket_channel.dart';

void main() async {
var socket = WebSocketChannel.connect(Uri.parse('ws://localhost:4321'));
var client = Client(socket.cast<String>());

// The client won't subscribe to the input stream until you call `listen`.
// The returned Future won't complete until the connection is closed.
unawaited(client.listen());

// This calls the "count" method on the server. A Future is returned that
// will complete to the value contained in the server's response.
var count = await client.sendRequest('count');
print('Count is $count');

// Parameters are passed as a simple Map or, for positional parameters, an
// Iterable. Make sure they're JSON-serializable!
var echo = await client.sendRequest('echo', {'message': 'hello'});
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.
try {
await client.sendRequest('divide', {'dividend': 2, 'divisor': 0});
} on RpcException catch (error) {
print('RPC error ${error.code}: ${error.message}');
}
}
70 changes: 70 additions & 0 deletions example/main.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:json_rpc_2/json_rpc_2.dart';
import 'package:web_socket_channel/web_socket_channel.dart';

void main() {
var socket = WebSocketChannel.connect(Uri.parse('ws://localhost:4321'));

// The socket is a `StreamChannel<dynamic>` because it might emit binary
// `List<int>`, but JSON RPC 2 only works with Strings so we assert it only
// emits those by casting it.
var server = Server(socket.cast<String>());

// 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', (Parameters 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['message'].value;
});

// `Parameters` has methods for verifying argument types.
server.registerMethod('subtract', (Parameters params) {
// If "minuend" or "subtrahend" aren't numbers, this will reject the
// request.
return params['minuend'].asNum - params['subtrahend'].asNum;
});

// [Parameters] also supports optional arguments.
server.registerMethod('sort', (Parameters params) {
var list = params['list'].asList;
list.sort();
if (params['descendint'].asBoolOr(false)) {
return list.reversed;
} else {
return list;
}
});

// A method can send an error response by throwing a `RpcException`.
// Any positive number may be used as an application- defined error code.
const dividByZero = 1;
server.registerMethod('divide', (Parameters params) {
var divisor = params['divisor'].asNum;
if (divisor == 0) {
throw RpcException(dividByZero, 'Cannot divide by zero.');
}

return params['dividend'].asNum / divisor;
});

// To give you time to register all your methods, the server won't start
// listening for requests until you call `listen`. Messages are buffered until
// listen is called. The returned Future won't complete until the connection
// is closed.
server.listen();
}
3 changes: 2 additions & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: json_rpc_2
version: 2.2.0
version: 2.2.1-dev
description: >-
Utilities to write a client or server using the JSON-RPC 2.0 spec.
homepage: https://github.com/dart-lang/json_rpc_2
Expand All @@ -14,3 +14,4 @@ dependencies:
dev_dependencies:
pedantic: ^1.8.0
test: ^1.0.0
web_socket_channel: ^1.1.0

0 comments on commit 1fa5626

Please sign in to comment.