rpc_dart¶
rpc_dart is a transport-agnostic RPC framework for Dart. Write your service contracts once and run them over any transport — in-process, HTTP/2, WebSocket, or Dart Isolates — without changing the service code. It uses gRPC-compatible 5-byte message framing and supports all four RPC call patterns.
RPC Patterns¶
| Pattern | Signature |
|---|---|
| Unary | Future<Response> method(Request) |
| Server streaming | Stream<Response> method(Request) |
| Client streaming | Future<Response> method(Stream<Request>) |
| Bidirectional streaming | Stream<Response> method(Stream<Request>) |
Packages¶
| Package | Description |
|---|---|
rpc_dart |
Core framework: contracts, endpoints, transports interface, context |
rpc_dart_generator |
build_runner code generator — turns annotated interfaces into ready-to-use responders and callers |
rpc_dart_compression |
Cross-platform gzip codec (works on web/wasm) |
rpc_dart_opentelemetry |
OpenTelemetry interceptor with W3C Trace Context propagation |
rpc_dart_http2 |
HTTP/2 transport (native) |
rpc_dart_http |
HTTP/1.1 transport (cross-platform, web/wasm) |
rpc_dart_websocket |
WebSocket transport (cross-platform) |
rpc_dart_isolate |
Dart Isolate transport (IO + web workers) |
Installation¶
dependencies:
rpc_dart: ^2.6.1
dev_dependencies:
rpc_dart_generator: ^0.1.6
build_runner: any
Minimal Example¶
The shortest path to a working RPC call — unary, in-process, zero-copy (no serialization):
import 'package:rpc_dart/rpc_dart.dart';
// Shared types
class AddRequest { final int a, b; AddRequest(this.a, this.b); }
class AddResponse { final int result; AddResponse(this.result); }
// Server contract
final class CalculatorResponder extends RpcResponderContract {
CalculatorResponder() : super('Calculator');
@override
void setup() {
addUnaryMethod<AddRequest, AddResponse>(
methodName: 'add',
handler: (req, {context}) async => AddResponse(req.a + req.b),
);
}
}
void main() async {
final (callerTransport, responderTransport) = RpcInMemoryTransport.pair();
final server = RpcResponderEndpoint(transport: responderTransport);
server.registerServiceContract(CalculatorResponder());
server.start();
final callerEndpoint = RpcCallerEndpoint(transport: callerTransport);
final response = await callerEndpoint.unaryRequest<AddRequest, AddResponse>(
serviceName: 'Calculator',
methodName: 'add',
request: AddRequest(2, 3),
);
print(response.result); // 5
}
For real projects use the code generator to avoid writing boilerplate. See the Getting Started guide for a full walkthrough.