Client middleware intercepts outgoing calls, allowing you to execute logic before/after the call, modify metadata, inspect requests/responses, or implement retries.
Middleware is defined as an Async Generator.
Basic Middleware Structure
For unary and client streaming methods, call.next yields no items and returns a single response. For server streaming and bidirectional streaming, it yields each response.
import {ClientMiddlewareCall, CallOptions} from 'nice-grpc-web';
async function* middleware<Request, Response>(
call: ClientMiddlewareCall<Request, Response>,
options: CallOptions,
) {
if (!call.responseStream) {
// Unary or Client Streaming
const response = yield* call.next(call.request, options);
return response;
} else {
// Server Streaming or Bidirectional
for await (const response of call.next(call.request, options)) {
yield response;
}
return;
}
}
Using a Client Factory
To attach middleware, use createClientFactory. Middleware attached first is invoked last (it wraps the subsequent ones).
import {createClientFactory} from 'nice-grpc-web';
const clientFactory = createClientFactory().use(middleware1).use(middleware2);
// Create multiple clients from one factory
const client1 = clientFactory.create(Service1, channel1);
const client2 = clientFactory.create(Service2, channel2);
import {ClientMiddlewareCall, CallOptions} from 'nice-grpc-web';
async function* middleware<Request, Response>(
call: ClientMiddlewareCall<Request, Response>,
options: CallOptions,
) {
if (!call.responseStream) {
const response = yield* call.next(call.request, options);
return response;
} else {
for await (const response of call.next(call.request, options)) {
yield response;
}
return;
}
}