Server-side gRPC functionality including service registration, handler functions, server lifecycle management, and support for all call types with interceptors and credential handling.
The main server class for hosting gRPC services with support for multiple services, interceptors, and flexible binding options.
/**
* Main gRPC server class for hosting services
*/
class Server {
/**
* Create a new gRPC server
* @param options - Optional server configuration
*/
constructor(options?: Partial<ServerOptions>);
/**
* Register a service implementation with the server
* @param service - Service definition from proto loading
* @param implementation - Object containing handler functions
*/
addService<Implementation extends UntypedServiceImplementation>(
service: ServiceDefinition,
implementation: Implementation
): void;
/**
* Bind the server to a port with credentials (async)
* @param port - Address to bind to (host:port format)
* @param creds - Server credentials for the binding
* @param callback - Called when binding completes
*/
bindAsync(
port: string,
creds: ServerCredentials,
callback: (error: Error | null, port: number) => void
): void;
/**
* Start accepting requests on bound ports
*/
start(): void;
/**
* Gracefully shutdown the server, waiting for active calls to complete
* @param callback - Called when shutdown completes
*/
tryShutdown(callback: (error?: Error) => void): void;
/**
* Forcefully shutdown the server, terminating active calls
*/
forceShutdown(): void;
}Configuration options for server instances including interceptors and channel options.
interface ServerOptions extends ChannelOptions {
/** Array of server interceptors to apply to all calls */
interceptors?: ServerInterceptor[];
}Interface for registering service handlers with the server.
interface UntypedServiceImplementation {
[methodName: string]: UntypedHandleCall;
}
type UntypedHandleCall =
| handleUnaryCall<any, any>
| handleClientStreamingCall<any, any>
| handleServerStreamingCall<any, any>
| handleBidiStreamingCall<any, any>;Type-safe handler function signatures for different call types.
Handle request-response style calls where client sends one message and expects one response.
/**
* Handler for unary (request-response) calls
* @param call - The server call object containing request and metadata
* @param callback - Function to call with response or error
*/
type handleUnaryCall<RequestType, ResponseType> = (
call: ServerUnaryCall<RequestType, ResponseType>,
callback: sendUnaryData<ResponseType>
) => void;
/**
* Callback for sending unary responses
* @param error - Error if call failed, null for success
* @param value - Response value for successful calls
* @param trailer - Optional trailing metadata
* @param flags - Optional response flags
*/
type sendUnaryData<ResponseType> = (
error: ServiceError | null,
value?: ResponseType | null,
trailer?: Metadata,
flags?: number
) => void;Usage Example:
const server = new Server();
server.addService(serviceDefinition, {
sayHello: (call, callback) => {
console.log("Received request from:", call.getPeer());
console.log("Request metadata:", call.metadata.getMap());
const response = {
message: `Hello ${call.request.name}!`
};
// Send successful response
callback(null, response);
// Or send error response
// callback({
// code: status.INVALID_ARGUMENT,
// details: "Name cannot be empty"
// });
}
});Handle calls where client sends multiple messages and expects one response.
/**
* Handler for client streaming calls
* @param call - The server readable stream for receiving client messages
* @param callback - Function to call with final response or error
*/
type handleClientStreamingCall<RequestType, ResponseType> = (
call: ServerReadableStream<RequestType, ResponseType>,
callback: sendUnaryData<ResponseType>
) => void;Usage Example:
server.addService(serviceDefinition, {
uploadData: (call, callback) => {
const chunks: string[] = [];
call.on('data', (request) => {
chunks.push(request.chunk);
console.log("Received chunk:", request.chunk);
});
call.on('end', () => {
const response = {
totalSize: chunks.join('').length,
chunkCount: chunks.length
};
callback(null, response);
});
call.on('error', (error) => {
console.error("Upload failed:", error);
callback(error);
});
}
});Handle calls where client sends one message and server responds with multiple messages.
/**
* Handler for server streaming calls
* @param call - The server writable stream for sending responses
*/
type handleServerStreamingCall<RequestType, ResponseType> = (
call: ServerWritableStream<RequestType, ResponseType>
) => void;Usage Example:
server.addService(serviceDefinition, {
downloadData: (call) => {
console.log("Download request:", call.request);
// Send multiple responses
for (let i = 0; i < 10; i++) {
call.write({
chunk: `data-chunk-${i}`,
progress: (i + 1) / 10
});
}
// End the stream
call.end();
}
});Handle calls where both client and server can send multiple messages simultaneously.
/**
* Handler for bidirectional streaming calls
* @param call - The server duplex stream for sending and receiving messages
*/
type handleBidiStreamingCall<RequestType, ResponseType> = (
call: ServerDuplexStream<RequestType, ResponseType>
) => void;Usage Example:
server.addService(serviceDefinition, {
chat: (call) => {
console.log("Chat session started with:", call.getPeer());
call.on('data', (request) => {
console.log("Received message:", request.message);
// Echo the message back
call.write({
message: `Echo: ${request.message}`,
timestamp: new Date().toISOString()
});
});
call.on('end', () => {
console.log("Chat session ended");
call.end();
});
call.on('error', (error) => {
console.error("Chat error:", error);
});
}
});Server-side representations of different call types with request access and metadata handling.
Server-side representation of unary calls with request data and metadata access.
interface ServerUnaryCall<RequestType, ResponseType> {
/** The client request data */
request: RequestType;
/** Request metadata sent by client */
metadata: Metadata;
/** Get the peer address of the client */
getPeer(): string;
/** Send initial metadata to client */
sendMetadata(responseMetadata: Metadata): void;
/** Check if the call has been cancelled */
isCancelled(): boolean;
}Server-side client streaming call for receiving multiple messages from client.
interface ServerReadableStream<RequestType, ResponseType> extends Readable {
/** Request metadata sent by client */
metadata: Metadata;
/** Get the peer address of the client */
getPeer(): string;
/** Send initial metadata to client */
sendMetadata(responseMetadata: Metadata): void;
/** Check if the call has been cancelled */
isCancelled(): boolean;
}Server-side server streaming call for sending multiple messages to client.
interface ServerWritableStream<RequestType, ResponseType> extends Writable {
/** The client request data */
request: RequestType;
/** Request metadata sent by client */
metadata: Metadata;
/** Get the peer address of the client */
getPeer(): string;
/** Send initial metadata to client */
sendMetadata(responseMetadata: Metadata): void;
/** Check if the call has been cancelled */
isCancelled(): boolean;
}Server-side bidirectional streaming call for sending and receiving multiple messages.
interface ServerDuplexStream<RequestType, ResponseType> extends Duplex {
/** Request metadata sent by client */
metadata: Metadata;
/** Get the peer address of the client */
getPeer(): string;
/** Send initial metadata to client */
sendMetadata(responseMetadata: Metadata): void;
/** Check if the call has been cancelled */
isCancelled(): boolean;
}Servers can send structured error responses with gRPC status codes and metadata.
interface ServerErrorResponse {
/** gRPC status code */
code: status;
/** Detailed error message */
details: string;
/** Optional trailing metadata */
metadata?: Metadata;
}Error Response Example:
server.addService(serviceDefinition, {
validateInput: (call, callback) => {
if (!call.request.data) {
callback({
code: status.INVALID_ARGUMENT,
details: "Data field is required",
metadata: new Metadata()
});
return;
}
// Process valid input
callback(null, { result: "success" });
}
});Complete server lifecycle with binding, starting, and graceful shutdown.
Complete Server Example:
import { Server, ServerCredentials, status } from "@grpc/grpc-js";
const server = new Server();
// Add service implementation
server.addService(serviceDefinition, {
// Service handlers here
});
// Bind to port
server.bindAsync(
"0.0.0.0:50051",
ServerCredentials.createInsecure(),
(error, port) => {
if (error) {
console.error("Failed to bind server:", error);
return;
}
console.log(`Server bound to port ${port}`);
server.start();
console.log("Server started");
}
);
// Graceful shutdown
process.on('SIGINT', () => {
console.log("Shutting down server...");
server.tryShutdown((error) => {
if (error) {
console.error("Error during shutdown:", error);
server.forceShutdown();
} else {
console.log("Server shut down gracefully");
}
process.exit(0);
});
});Advanced server functionality for connection management and injection.
interface ConnectionInjector {
/** Inject a connection into the server */
injectConnection(connection: any): void;
}