Skip to content

HTTP/2 Transport

rpc_dart_http2 provides an HTTP/2 transport for native platforms. It supports all four RPC patterns, multiplexes streams over a single TCP connection, and uses gRPC-compatible pseudo-headers — making it interoperable with any gRPC server or client that speaks the wire protocol.

Native only

rpc_dart_http2 depends on dart:io and does not compile to JS or Wasm. For web clients use WebSocket or HTTP/1.1.


Installation

dependencies:
  rpc_dart_http2: <latest>

Server

RpcHttp2Server accepts incoming TCP connections, wraps each in RpcHttp2ResponderTransport, creates a RpcResponderEndpoint, and fires onEndpointCreated so you can register contracts.

Quick setup

import 'package:rpc_dart_http2/rpc_dart_http2.dart';

final server = RpcHttp2Server.createWithContracts(
  host: '0.0.0.0',
  port: 8080,
  contracts: [CalculatorResponder()],
);

await server.start();

// later
await server.stop();

Manual setup

Use the default constructor when you need per-connection logic — registering contracts based on auth headers, wrapping transports, etc.:

final server = RpcHttp2Server(
  host: '0.0.0.0',
  port: 8080,
  onEndpointCreated: (endpoint) {
    endpoint.registerServiceContract(CalculatorResponder());
    endpoint.addInterceptor(OtelRpcInterceptor(tracer: tracer));
  },
  onConnectionError: (error, stackTrace) => print('Error: $error'),
  onConnectionOpened: (socket) => print('Connected: ${socket.remoteAddress}'),
  onConnectionClosed: (socket) => print('Closed: ${socket.remoteAddress}'),
);

await server.start();

transportWrapper lets you wrap every new transport before the endpoint sees it — useful for encryption overlays:

RpcHttp2Server(
  port: 8080,
  transportWrapper: (inner, socket) => EncryptedTransport(inner),
  onEndpointCreated: (endpoint) {
    endpoint.registerServiceContract(MyResponder());
  },
);

Client

// TLS (production)
final transport = await RpcHttp2CallerTransport.secureConnect(
  host: 'api.example.com',
  port: 443,
);

// Plain TCP (local dev, internal network)
final transport = await RpcHttp2CallerTransport.connect(
  host: 'localhost',
  port: 8080,
);

final caller = CalculatorContractCaller(
  RpcCallerEndpoint(transport: transport),
);

final result = await caller.sum(SumRequest(values: [1, 2, 3]));

await caller.endpoint.close();

Reconnection

The caller transport stores a connection factory internally and can reconnect after a drop:

final status = await transport.reconnect();
if (status.isHealthy) {
  print('Reconnected');
}

Stream ID counters reset on reconnect.


Security Policy

Both client and server accept RpcSecurityPolicy to limit resource usage:

RpcHttp2CallerTransport.secureConnect(
  host: 'api.example.com',
  port: 443,
  policy: RpcSecurityPolicy(
    maxActiveStreams: 100,
    maxMessageLengthBytes: 4 * 1024 * 1024,
  ),
);

gRPC Compatibility

The transport maps RPC method paths to HTTP/2 pseudo-headers in the gRPC format:

:method    = POST
:path      = /ServiceName/MethodName
:scheme    = https
:authority = host

A rpc_dart server with HTTP/2 transport can be called from any standard gRPC client (Go, Java, Python, etc.) — and vice versa.