gRPC-Web is a JavaScript client runtime library that enables web applications to communicate directly with gRPC services through a special gateway proxy (typically Envoy). It provides both unary and server-side streaming RPC capabilities with support for multiple wire formats (grpc-web-text and binary protobuf), TypeScript definitions for type safety, and flexible import styles including CommonJS and Closure Compiler compatibility.
npm install grpc-webimport {
GrpcWebClientBase,
MethodDescriptor,
StatusCode,
RpcError,
MethodType,
CallOptions
} from "grpc-web";For CommonJS:
const {
GrpcWebClientBase,
MethodDescriptor,
StatusCode,
RpcError,
MethodType,
CallOptions
} = require("grpc-web");import { GrpcWebClientBase, MethodDescriptor, MethodType } from "grpc-web";
// Create a client
const client = new GrpcWebClientBase({
format: 'text', // or 'binary'
suppressCorsPreflight: false,
withCredentials: false
});
// Define a method descriptor
const methodDescriptor = new MethodDescriptor(
'/package.Service/Method',
MethodType.UNARY,
RequestType,
ResponseType,
(request) => request.serializeBinary(),
(bytes) => ResponseType.deserializeBinary(bytes)
);
// Make a unary call
const response = await client.thenableCall(
'https://api.example.com/package.Service/Method',
requestMessage,
{}, // metadata
methodDescriptor
);
// Make a server streaming call
const stream = client.serverStreaming(
'https://api.example.com/package.Service/StreamMethod',
requestMessage,
{}, // metadata
methodDescriptor
);
stream.on('data', (response) => {
console.log('Received:', response);
});
stream.on('error', (error) => {
console.error('Error:', error);
});
stream.on('end', () => {
console.log('Stream ended');
});gRPC-Web is built around several key components:
AbstractClientBase interface and GrpcWebClientBase implementation providing the core client functionalityMethodDescriptor class defining RPC method metadata including serialization/deserialization functionsClientReadableStream interface for handling server-side streaming responses with event-based APIRpcError class and StatusCode enum for comprehensive gRPC status code managementCore client classes for creating and managing gRPC-Web connections with comprehensive configuration options.
abstract class AbstractClientBase {
abstract rpcCall<REQ, RESP>(
method: string,
request: REQ,
metadata: Metadata,
methodDescriptor: MethodDescriptor<REQ, RESP>,
callback: (err: RpcError, response: RESP) => void
): ClientReadableStream<RESP>;
abstract thenableCall<REQ, RESP>(
method: string,
request: REQ,
metadata: Metadata,
methodDescriptor: MethodDescriptor<REQ, RESP>,
options?: PromiseCallOptions
): Promise<RESP>;
abstract serverStreaming<REQ, RESP>(
method: string,
request: REQ,
metadata: Metadata,
methodDescriptor: MethodDescriptor<REQ, RESP>
): ClientReadableStream<RESP>;
}
class GrpcWebClientBase extends AbstractClientBase {
constructor(options?: GrpcWebClientBaseOptions);
}
interface GrpcWebClientBaseOptions {
format?: string;
suppressCorsPreflight?: boolean;
withCredentials?: boolean;
unaryInterceptors?: UnaryInterceptor<unknown, unknown>[];
streamInterceptors?: StreamInterceptor<unknown, unknown>[];
}Method descriptors define gRPC method metadata and request/response handling for type-safe RPC operations.
class MethodDescriptor<REQ, RESP> {
constructor(
name: string,
methodType: string,
requestType: new (...args: unknown[]) => REQ,
responseType: new (...args: unknown[]) => RESP,
requestSerializeFn: any,
responseDeserializeFn: any
);
getName(): string;
createRequest(
requestMessage: REQ,
metadata?: Metadata,
callOptions?: CallOptions
): Request<REQ, RESP>;
createUnaryResponse(
responseMessage: RESP,
metadata?: Metadata,
status?: Status
): UnaryResponse<REQ, RESP>;
}
interface Request<REQ, RESP> {
getRequestMessage(): REQ;
getMethodDescriptor(): MethodDescriptor<REQ, RESP>;
getMetadata(): Metadata;
getCallOptions(): CallOptions | undefined;
withMetadata(key: string, value: string): Request<REQ, RESP>;
withGrpcCallOption<VALUE>(name: string, value: VALUE): Request<REQ, RESP>;
}
interface UnaryResponse<REQ, RESP> {
getResponseMessage(): RESP;
getMetadata(): Metadata;
getMethodDescriptor(): MethodDescriptor<REQ, RESP>;
getStatus(): Status;
}Method Descriptors and Requests
Server-side streaming support with event-driven API for handling real-time data streams from gRPC services.
interface ClientReadableStream<RESP> {
on(eventType: "data", callback: (response: RESP) => void): ClientReadableStream<RESP>;
on(eventType: "error", callback: (err: RpcError) => void): ClientReadableStream<RESP>;
on(eventType: "status", callback: (status: Status) => void): ClientReadableStream<RESP>;
on(eventType: "metadata", callback: (metadata: Metadata) => void): ClientReadableStream<RESP>;
on(eventType: "end", callback: () => void): ClientReadableStream<RESP>;
removeListener(eventType: "data", callback: (response: RESP) => void): void;
removeListener(eventType: "error", callback: (err: RpcError) => void): void;
removeListener(eventType: "status", callback: (status: Status) => void): void;
removeListener(eventType: "metadata", callback: (metadata: Metadata) => void): void;
removeListener(eventType: "end", callback: () => void): void;
cancel(): void;
}Comprehensive error handling system with gRPC status codes and HTTP status mapping for robust error management.
class RpcError extends Error {
constructor(code: StatusCode, message: string, metadata?: Metadata);
code: StatusCode;
metadata: Metadata;
}
enum StatusCode {
OK = 0,
CANCELLED = 1,
UNKNOWN = 2,
INVALID_ARGUMENT = 3,
DEADLINE_EXCEEDED = 4,
NOT_FOUND = 5,
ALREADY_EXISTS = 6,
PERMISSION_DENIED = 7,
RESOURCE_EXHAUSTED = 8,
FAILED_PRECONDITION = 9,
ABORTED = 10,
OUT_OF_RANGE = 11,
UNIMPLEMENTED = 12,
INTERNAL = 13,
UNAVAILABLE = 14,
DATA_LOSS = 15,
UNAUTHENTICATED = 16
}
interface Status {
code: number;
details: string;
metadata?: Metadata;
}Interceptor system for implementing middleware functionality in both unary and streaming RPC calls.
interface UnaryInterceptor<REQ, RESP> {
intercept(
request: Request<REQ, RESP>,
invoker: (request: Request<REQ, RESP>) => Promise<UnaryResponse<REQ, RESP>>
): Promise<UnaryResponse<REQ, RESP>>;
}
interface StreamInterceptor<REQ, RESP> {
intercept(
request: Request<REQ, RESP>,
invoker: (request: Request<REQ, RESP>) => ClientReadableStream<RESP>
): ClientReadableStream<RESP>;
}interface Metadata {
[s: string]: string;
}
interface PromiseCallOptions {
readonly signal?: AbortSignal;
}
class CallOptions {
constructor(options?: { [key: string]: any });
setOption(name: string, value: any): void;
get(name: string): any;
removeOption(name: string): void;
getKeys(): string[];
}
namespace MethodType {
const UNARY: string;
const SERVER_STREAMING: string;
const BIDI_STREAMING: string;
}