### Install nice-grpc-server-reflection Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-server-reflection/README.md Install the package using npm. ```bash npm install nice-grpc-server-reflection ``` -------------------------------- ### Implement and Run a gRPC Server with nice-grpc Source: https://context7.com/deeplay-io/nice-grpc/llms.txt This example demonstrates a full gRPC server setup. It includes implementing unary, server streaming, and client streaming methods, applying logging middleware, and handling graceful shutdown with SIGTERM. ```typescript import {createServer, ServerError, Status, ServerMiddlewareCall, CallContext} from 'nice-grpc'; import { ExampleServiceDefinition, ExampleServiceImplementation, ExampleRequest, ExampleResponse, DeepPartial, } from './compiled_proto/example'; // --- Service implementation --- const exampleServiceImpl: ExampleServiceImplementation = { // Unary method async exampleUnaryMethod( request: ExampleRequest, context: CallContext, ): Promise> { if (!request.id) { throw new ServerError(Status.INVALID_ARGUMENT, 'id is required'); } // Read incoming metadata const traceId = context.metadata.get('x-trace-id'); // Send response header context.header.set('x-server-id', 'node-1'); // response trailer sent automatically on return context.trailer.set('x-duration-ms', '42'); return {result: `Hello, ${request.id}`}; }, // Server streaming method async *exampleStreamingMethod( request: ExampleRequest, context: CallContext, ): AsyncIterable> { for (let i = 0; i < 5; i++) { // abort-controller-x delay respects AbortSignal await import('abort-controller-x').then(({delay}) => delay(context.signal, 500)); yield {result: `item ${i}`}; } }, // Client streaming method async exampleClientStreamingMethod( requests: AsyncIterable, context: CallContext, ): Promise> { const ids: string[] = []; for await (const req of requests) { ids.push(req.id); } return {result: `Received: ${ids.join(', ')}`}; }, }; // --- Logging middleware --- async function* loggingMiddleware( call: ServerMiddlewareCall, context: CallContext, ) { console.log(`[server] ${call.method.path} start`); try { const result = yield* call.next(call.request, context); console.log(`[server] ${call.method.path} OK`); return result; } catch (err) { console.error(`[server] ${call.method.path} error:`, err); throw err; } } // --- Wire everything together --- const server = createServer().use(loggingMiddleware); server.add(ExampleServiceDefinition, exampleServiceImpl); await server.listen('0.0.0.0:50051'); console.log('Server listening on :50051'); // Graceful shutdown process.on('SIGTERM', async () => { await server.shutdown(); }); ``` -------------------------------- ### Install nice-grpc-client-middleware-devtools Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-client-middleware-devtools/README.md Install the package using npm. ```bash npm install nice-grpc-client-middleware-devtools ``` -------------------------------- ### Install nice-grpc-client-middleware-deadline Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-client-middleware-deadline/README.md Install the package using npm. ```bash npm install nice-grpc-client-middleware-deadline ``` -------------------------------- ### Install google-protobuf dependencies Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc/README.md Install the necessary tools for using google-protobuf with nice-grpc. ```bash npm install google-protobuf npm install --save-dev grpc-tools grpc_tools_node_protoc_ts @types/google-protobuf ``` -------------------------------- ### Install nice-grpc-web Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-web/README.md Install the nice-grpc-web package using npm. ```bash npm install nice-grpc-web ``` -------------------------------- ### Create and Start nice-grpc Server Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc/README.md Create a new `nice-grpc` server instance, add the service definition and its implementation, and then start listening on a specified address. This is the standard way to launch a gRPC server. ```typescript import {createServer} from 'nice-grpc'; import {ExampleServiceDefinition} from './compiled_proto/example'; const server = createServer(); server.add(ExampleServiceDefinition, exampleServiceImpl); await server.listen('0.0.0.0:8080'); ``` -------------------------------- ### Install nice-grpc Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc/README.md Install the nice-grpc package using npm. ```bash npm install nice-grpc ``` -------------------------------- ### Install google-protobuf dependencies Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-web/README.md Install necessary tools for compiling Protobuf files with google-protobuf. ```bash npm install google-protobuf npm install --save-dev grpc-tools ts-protoc-gen @types/google-protobuf ``` -------------------------------- ### Install ts-proto dependencies Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-web/README.md Install necessary tools for compiling Protobuf files with ts-proto. ```bash npm install protobufjs long npm install --save-dev grpc-tools ts-proto ``` -------------------------------- ### Install nice-grpc-client-middleware-retry Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-client-middleware-retry/README.md Install the retry middleware package using npm. ```bash npm install nice-grpc-client-middleware-retry ``` -------------------------------- ### Install nice-grpc-common Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-common/README.md Install the package using npm. This package is intended for middleware libraries. ```bash npm install nice-grpc-common ``` -------------------------------- ### Default Call Options Example Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc/README.md Example of setting default call options for all methods or specific methods. ```APIDOC ```ts const client = createClient(ExampleServiceDefinition, channel, { '*': { // applies for all methods deadline: 30_000, }, exampleUnaryMethod: { // applies for single method deadline: 10_000, }, }); ``` ``` -------------------------------- ### Logging Client Middleware Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-web/README.md A client middleware example that logs the start, end, and any errors (including aborts and gRPC status codes) of outgoing calls. It provides detailed insights into the call lifecycle. ```typescript import { ClientMiddlewareCall, CallOptions, ClientError, Status, } from 'nice-grpc-web'; import {isAbortError} from 'abort-controller-x'; async function* loggingMiddleware( call: ClientMiddlewareCall, options: CallOptions, ) { const {path} = call.method; console.log('Client call', path, 'start'); try { const result = yield* call.next(call.request, options); console.log('Client call', path, 'end: OK'); return result; } catch (error) { if (error instanceof ClientError) { console.log( 'Client call', path, `end: ${Status[error.code]}: ${error.details}`, ); } else if (isAbortError(error)) { console.log('Client call', path, 'cancel'); } else { console.log('Client call', path, `error: ${error?.stack}`); } throw error; } } ``` -------------------------------- ### Logging Client Middleware Example Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc/README.md A client middleware that logs the start, end, and any errors of outgoing calls. It handles successful calls, client errors, and abort signals, providing visibility into call lifecycle. ```typescript import { ClientMiddlewareCall, CallOptions, ClientError, Status, } from 'nice-grpc'; import {isAbortError} from 'abort-controller-x'; async function* loggingMiddleware( call: ClientMiddlewareCall, options: CallOptions, ) { const {path} = call.method; console.log('Client call', path, 'start'); try { const result = yield* call.next(call.request, options); console.log('Client call', path, 'end: OK'); return result; } catch (error) { if (error instanceof ClientError) { console.log( 'Client call', path, `end: ${Status[error.code]}: ${error.details}`, ); } else if (isAbortError(error)) { console.log('Client call', path, 'cancel'); } else { console.log('Client call', path, `error: ${error?.stack}`); } throw error; } } ``` -------------------------------- ### Call gRPC Method Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc/README.md Example of calling a unary gRPC method on a client instance created with nice-grpc. ```typescript const response = await client.exampleUnaryMethod(request); ``` -------------------------------- ### Default Metadata Middleware Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc/README.md Example of using middleware to add default metadata like Authorization. ```APIDOC ```ts const token = '...'; const client = createClientFactory().use((call, options) => call.next(call.request, { ...options, metadata: Metadata(options.metadata).set( 'Authorization', `Bearer ${token}`), }), ); ``` ``` -------------------------------- ### Metadata Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-web/README.md Details how to send request metadata and receive response headers and trailers using the `Metadata` object. It shows an example of setting metadata and handling header/trailer callbacks. ```APIDOC ## Metadata Client can send request metadata and receive response header and trailer: ```ts import {Metadata} from 'nice-grpc-web'; const response = await client.exampleUnaryMethod(request, { metadata: Metadata({key: 'value'}), onHeader(header: Metadata) { // ... }, onTrailer(trailer: Metadata) { // ... }, }); ``` > **Note** Most `fetch` implementations only receive response header when the > first chunk of the response body is received. This means that `onHeader` will > be called just before the response (or the first response message in case of > server streaming) is received, even if the server sends the header before > sending the response. ``` -------------------------------- ### Define Client Streaming RPC Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-web/README.md Example Protobuf definition for a service method that accepts a stream of requests. ```proto service ExampleService { rpc ExampleClientStreamingMethod(stream ExampleRequest) returns (ExampleResponse) {}; } ``` -------------------------------- ### Define Server Streaming RPC Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-web/README.md Example Protobuf definition for a service method that returns a stream of responses. ```proto service ExampleService { rpc ExampleStreamingMethod(ExampleRequest) returns (stream ExampleResponse) {}; } ``` -------------------------------- ### Server Logging Middleware Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc/README.md Implement a server middleware to log the start, end, and any errors of incoming calls. Handles successful calls, ServerErrors, and abort errors. ```typescript import { Status, ServerError, ServerMiddlewareCall, CallContext, } from 'nice-grpc'; import {isAbortError} from 'abort-controller-x'; async function* loggingMiddleware( call: ServerMiddlewareCall, context: CallContext, ) { const {path} = call.method; console.log('Server call', path, 'start'); try { const result = yield* call.next(call.request, context); console.log('Server call', path, 'end: OK'); return result; } catch (error) { if (error instanceof ServerError) { console.log( 'Server call', path, `end: ${Status[error.code]}: ${error.details}`, ); } else if (isAbortError(error)) { console.log('Server call', path, 'cancel'); } else { console.log('Server call', path, `error: ${error?.stack}`); } throw error; } } ``` -------------------------------- ### Customizing Client Prometheus Metrics Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-prometheus/README.md Integrate custom Prometheus metric instances for your gRPC client. This example shows how to define a custom histogram with specific buckets and registers it with the client factory. ```ts import {createClientFactory} from 'nice-grpc'; import { labelNamesWithCode, prometheusClientMiddleware, } from 'nice-grpc-prometheus'; import {Histogram, Registry} from 'prom-client'; const registry = new Registry(); const clientHandlingSecondsMetric = new Histogram({ registers: [registry], name: 'custom_grpc_client_handling_seconds', help: 'Custom histogram of response latency (seconds) of the gRPC until it is finished by the application.', labelNames: labelNamesWithCode, buckets: [0.1, 0.5, 1, 2, 3, 5, 10], }); const clientFactory = createClientFactory() .use(prometheusClientMiddleware({clientHandlingSecondsMetric})) .use(/* ... other middleware */); ``` -------------------------------- ### Creating a Client Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-web/README.md Demonstrates how to create a gRPC client instance using either ts-proto or google-protobuf compiled files. It shows the necessary imports and the basic structure for client creation. ```APIDOC ## Creating a Client ### Using ts-proto ```ts import {createChannel, createClient} from 'nice-grpc-web'; import {ExampleServiceDefinition} from './compiled_proto/example'; import type {ExampleServiceClient} from './compiled_proto/example'; const channel = createChannel('http://localhost:8080'); const client: ExampleServiceClient = createClient( ExampleServiceDefinition, channel, ); ``` ### Using google-protobuf ```ts import {createChannel, createClient, Client} from 'nice-grpc'; import { ExampleService, IExampleService, } from './compiled_proto/example_grpc_pb'; const channel = createChannel('http://localhost:8080'); const client: Client = createClient(ExampleService, channel); ``` ``` -------------------------------- ### Creating a Client with Multiple Middleware Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc/README.md Demonstrates how to create a client using a factory and applying multiple middleware functions in sequence. Middleware attached first is invoked last. ```typescript import {createClientFactory} from 'nice-grpc'; const client = createClientFactory() .use(middleware1) .use(middleware2) .create(ExampleService, channel); ``` -------------------------------- ### Create gRPC Client with google-protobuf Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc/README.md Sets up a gRPC client using nice-grpc and a protobuf definition compiled with google-protobuf. Requires creating a channel and then the client. ```typescript import {createChannel, createClient, Client} from 'nice-grpc'; import { ExampleService, IExampleService, } from './compiled_proto/example_grpc_pb'; const channel = createChannel('localhost:8080'); const client: Client = createClient(ExampleService, channel); ``` -------------------------------- ### Create gRPC Client with ts-proto Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc/README.md Sets up a gRPC client using nice-grpc and a protobuf definition compiled with ts-proto. Requires creating a channel and then the client. ```typescript import {createChannel, createClient} from 'nice-grpc'; import {ExampleServiceDefinition} from './compiled_proto/example'; import type {ExampleServiceClient} from './compiled_proto/example'; const channel = createChannel('localhost:8080'); const client: ExampleServiceClient = createClient( ExampleServiceDefinition, channel, ); ``` -------------------------------- ### Implement gRPC Service with ts-proto Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc/README.md Implement a gRPC service using the `ExampleServiceImplementation` interface generated by `ts-proto`. Ensure the method signature matches the generated types, returning `DeepPartial`. ```typescript import { ExampleServiceImplementation, ExampleRequest, ExampleResponse, DeepPartial, } from './compiled_proto/example'; const exampleServiceImpl: ExampleServiceImplementation = { async exampleUnaryMethod( request: ExampleRequest, ): Promise> { // ... method logic return response; }, }; ``` -------------------------------- ### Create Client with google-protobuf Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-web/README.md Instantiate a gRPC client using google-protobuf compiled definitions and a channel. Note the different import paths and type definitions. ```typescript import {createChannel, createClient, Client} from 'nice-grpc'; import { ExampleService, IExampleService, } from './compiled_proto/example_grpc_pb'; const channel = createChannel('http://localhost:8080'); const client: Client = createClient(ExampleService, channel); ``` -------------------------------- ### Create Client with Multiple Middleware Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-web/README.md Illustrates creating a gRPC client using a factory, applying multiple middleware functions in sequence. The order of `use` calls determines the invocation order. ```typescript import {createClientFactory} from 'nice-grpc-web'; const client = createClientFactory() .use(middleware1) .use(middleware2) .create(ExampleService, channel); ``` -------------------------------- ### Errors Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-web/README.md Explains how gRPC errors are handled on the client side, specifically focusing on `ClientError` which contains the status code and description. It provides an example of catching and inspecting errors. ```APIDOC ## Errors Client calls may throw gRPC errors represented as `ClientError`, that contain status code and description. ```ts import {ClientError, Status} from 'nice-grpc-web'; import {ExampleResponse} from './compiled_proto/example'; let response: ExampleResponse | null; try { response = await client.exampleUnaryMethod(request); } catch (error: unknown) { if (error instanceof ClientError && error.code === Status.NOT_FOUND) { response = null; } else { throw error; } } ``` ``` -------------------------------- ### Waiting for Channel Ready Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc/README.md How to wait for a channel to be ready before making calls, useful for startup verification. ```APIDOC ```ts import {createChannel, waitForChannelReady} from 'nice-grpc'; const channel = createChannel('localhost:8080'); await waitForChannelReady(channel, new Date(Date.now() + 5000)); ``` ``` -------------------------------- ### Implement gRPC Service with google-protobuf Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc/README.md Implement a gRPC service when using `google-protobuf` for Protobuf compilation. Use the `ServiceImplementation` type from `nice-grpc` and ensure method signatures align with the generated `_pb` and `_grpc_pb` files. ```typescript import {ServiceImplementation} from 'nice-grpc'; import {ExampleRequest, ExampleResponse} from './compiled_proto/example_pb'; import {IExampleService} from './compiled_proto/example_grpc_pb'; const exampleServiceImpl: ServiceImplementation = { async exampleUnaryMethod(request: ExampleRequest): Promise { // ... method logic return response; }, }; ``` -------------------------------- ### Create Client with ts-proto Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-web/README.md Instantiate a gRPC client using ts-proto compiled definitions and a channel. Ensure the service definition and client type are correctly imported. ```typescript import {createChannel, createClient} from 'nice-grpc-web'; import {ExampleServiceDefinition} from './compiled_proto/example'; import type {ExampleServiceClient} from './compiled_proto/example'; const channel = createChannel('http://localhost:8080'); const client: ExampleServiceClient = createClient( ExampleServiceDefinition, channel, ); ``` -------------------------------- ### Handle Client Errors Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-web/README.md Catch and handle gRPC errors, specifically ClientError, which contains the status code and description. This example shows how to gracefully handle a NOT_FOUND error. ```typescript import {ClientError, Status} from 'nice-grpc-web'; import {ExampleResponse} from './compiled_proto/example'; let response: ExampleResponse | null; try { response = await client.exampleUnaryMethod(request); } catch (error: unknown) { if (error instanceof ClientError && error.code === Status.NOT_FOUND) { response = null; } else { throw error; } } ``` -------------------------------- ### Handle RichClientError on Client Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-error-details/README.md Catch RichClientError on the client side to access detailed error information. This example demonstrates how to extract BadRequest field violations from the error details. ```typescript import {Status} from 'nice-grpc'; import {RichClientError, BadRequest} from 'nice-grpc-error-details'; const fieldViolations: BadRequest_FieldViolation[] = []; try { await client.exampleUnaryMethod(request); } catch (error: unknown) { if ( error instanceof RichClientError && error.code === Status.INVALID_ARGUMENT ) { // loop through error details to find `BadRequest` for (const detail of error.extra) { if (detail.$type === BadRequest.$type) { fieldViolations.push(...detail.fieldViolations); } } } else { throw error; } } ``` -------------------------------- ### Implement gRPC Service with Class (ts-proto) Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc/README.md Alternatively, implement a gRPC service by extending a class that adheres to the `ExampleServiceImplementation` interface generated by `ts-proto`. This provides a class-based approach to service implementation. ```typescript class ExampleServiceImpl implements ExampleServiceImplementation { async exampleUnaryMethod( request: ExampleRequest, ): Promise> { // ... method logic return response; } } ``` -------------------------------- ### Calling a Method Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-web/README.md Illustrates how to invoke a unary RPC method on the created client. It shows the basic syntax for making a call and handling the response. ```APIDOC ## Calling a Method ```ts const response = await client.exampleUnaryMethod(request); ``` With `ts-proto`, request is automatically wrapped with `fromPartial`. ``` -------------------------------- ### Throw RichServerError on Server Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-error-details/README.md Throw RichServerError from your service implementation methods to include specific error details. This example shows how to throw an INVALID_ARGUMENT error with a BadRequest detail. ```typescript import {ServerError, Status} from 'nice-grpc'; import {RichServerError, BadRequest} from 'nice-grpc-error-details'; const exampleServiceImpl: ServiceImplementation< typeof ExampleServiceDefinition > = { async exampleUnaryMethod( request: ExampleRequest, ): Promise> { if (!request.someField) throw new RichServerError( Status.INVALID_ARGUMENT, "Missing required field 'some_field'", [ BadRequest.fromPartial({ fieldViolations: [ { field: 'some_field', description: 'Field is required', }, ], }), ], ); // ... method logic }, }; ``` -------------------------------- ### Default Call Options Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-web/README.md Shows how to configure default call options, either for all methods or specific methods, when creating the client. This is useful for setting common configurations like deadlines. ```APIDOC ## Default Call Options When creating a client, you may specify default call options per method, or for all methods. This doesn't make much sense for built-in options, but may do for middleware, for example, [nice-grpc-client-middleware-deadline](/packages/nice-grpc-client-middleware-deadline): ```ts const client = createClient(ExampleServiceDefinition, channel, { '*': { // applies for all methods deadline: 30_000, }, exampleUnaryMethod: { // applies for single method deadline: 10_000, }, }); ``` To add default metadata, instead use a middleware that merges it with the metadata passed to the call: ```ts const token = '...'; const client = createClientFactory().use((call, options) => call.next(call.request, { ...options, metadata: Metadata(options.metadata).set( 'Authorization', `Bearer ${token}`), }), ); ``` ``` -------------------------------- ### Access and Set Metadata in CallContext Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc/README.md Access client-sent metadata via `context.metadata` and set response metadata in `context.header` and `context.trailer`. Metadata is managed using `Map`-like methods such as `get` and `set`. ```typescript const exampleServiceImpl: ExampleServiceImplementation = { async exampleUnaryMethod( request: ExampleRequest, context: CallContext, ): Promise> { // read client metadata const someValue = context.metadata.get('some-key'); // add metadata to header context.header.set('some-key', 'some-value'); // ... method logic // add metadata to trailer context.trailer.set('some-key', 'some-value'); return response; }, }; ``` -------------------------------- ### Reuse Client Factory for Multiple Clients Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-web/README.md Shows how to create a single client factory and reuse it to generate multiple clients for different services, potentially with the same set of middleware. ```typescript const clientFactory = createClientFactory().use(middleware); const client1 = clientFactory.create(Service1, channel1); const client2 = clientFactory.create(Service2, channel2); ``` -------------------------------- ### Channel Creation Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc/README.md Demonstrates creating gRPC channels with and without TLS. ```APIDOC ```ts import {createChannel, ChannelCredentials} from 'nice-grpc'; // Insecure connection createChannel('example.com:8080'); createChannel('http://example.com:8080'); createChannel('example.com:8080', ChannelCredentials.createInsecure()); // Secure connection (TLS) createChannel('https://example.com:8080'); createChannel('example.com:8080', ChannelCredentials.createSsl()); ``` Default ports are 80 for insecure and 443 for secure connections if omitted. ``` -------------------------------- ### Compile Protobuf with google-protobuf Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-web/README.md Generate JavaScript code and TypeScript definitions from a Protobuf file using google-protobuf. ```bash ./node_modules/.bin/grpc_tools_node_protoc \ --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts \ --js_out=import_style=commonjs,binary:./compiled_proto \ --ts_out=service=grpc-web:./compiled_proto \ --proto_path=./proto \ ./proto/example.proto ``` -------------------------------- ### Call Options Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-web/README.md Explains the `CallOptions` object that can be passed as an optional second argument to client methods. It covers metadata, cancellation signals, and callbacks for headers and trailers. ```APIDOC ## Call Options Each client method accepts `CallOptions` as an optional second argument, that has type: ```ts type CallOptions = { /** * Request metadata. */ metadata?: Metadata; /** * Signal that cancels the call once aborted. */ signal?: AbortSignal; /** * Called when header is received. */ onHeader?(header: Metadata): void; /** * Called when trailer is received. */ onTrailer?(trailer: Metadata): void; }; ``` Call options may be augmented by [Middleware](#middleware). ``` -------------------------------- ### Attach Middleware Per Client Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-web/README.md Demonstrates attaching different middleware to clients created from the same factory. Middleware attached directly to `create` are applied after the factory's middleware. ```typescript const factory = createClientFactory().use(middlewareA); const client1 = clientFactory.use(middlewareB).create(Service1, channel1); const client2 = clientFactory.use(middlewareC).create(Service2, channel2); ``` -------------------------------- ### Add ServerReflection Service to gRPC Server Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-server-reflection/README.md Integrate the ServerReflection service into your nice-grpc server. This involves reading a protoset file and specifying the fully-qualified names of the services to be exposed. ```typescript import {createServer} from 'nice-grpc'; import {ServerReflectionService, ServerReflection} from 'nice-grpc-server-reflection'; import * as fs from 'fs'; const server = createServer(); // add our own service server.add(MyService, myServiceImpl); // add server reflection service server.add( ServerReflectionService, ServerReflection( fs.readFileSync(path.join('path', 'to', 'protoset.bin')), // specify fully-qualified names of exposed services [MyService.fullName], ), ); ``` -------------------------------- ### Enable gRPC Server Reflection with ServerReflection Source: https://context7.com/deeplay-io/nice-grpc/llms.txt Use ServerReflection to implement the gRPC Server Reflection Protocol, allowing tools like grpcurl to discover services without needing .proto files. Load a pre-built descriptor set. ```typescript import {createServer} from 'nice-grpc'; import {ServerReflectionService, ServerReflection} from 'nice-grpc-server-reflection'; import {MyServiceDefinition} from './compiled_proto/my_service'; import * as fs from 'fs'; import * as path from 'path'; const server = createServer(); server.add(MyServiceDefinition, myServiceImpl); // Load the pre-built descriptor set (generated with --descriptor_set_out + --include_imports) server.add( ServerReflectionService, ServerReflection( fs.readFileSync(path.join(__dirname, 'protoset.bin')), [MyServiceDefinition.fullName], // expose only these services ), ); await server.listen('0.0.0.0:50051'); // Now usable with grpcurl without specifying .proto files: // grpcurl -plaintext localhost:50051 list // grpcurl -plaintext -d '{"id":"1"}' localhost:50051 my_package.MyService/MyMethod ``` -------------------------------- ### Create Node.js gRPC Channel and Client Source: https://context7.com/deeplay-io/nice-grpc/llms.txt Use `createChannel` to establish a connection and `createClient` to create a typed client stub. Supports insecure, TLS, and mTLS channels. Middleware can be applied using `createClientFactory`. Ensure channel readiness with `waitForChannelReady`. ```typescript import { createChannel, createClient, createClientFactory, ChannelCredentials, ClientError, ClientMiddlewareCall, CallOptions, Metadata, Status, waitForChannelReady, } from 'nice-grpc'; import {isAbortError} from 'abort-controller-x'; import { ExampleServiceDefinition, ExampleServiceClient, ExampleRequest, DeepPartial, } from './compiled_proto/example'; // Insecure channel (all equivalent) const channel = createChannel('localhost:50051'); // TLS channel const tlsChannel = createChannel('https://api.example.com'); // Explicit credentials const mtlsChannel = createChannel('api.example.com:443', ChannelCredentials.createSsl()); // Wait for channel readiness before first call (optional) await waitForChannelReady(channel, new Date(Date.now() + 5_000)); // Client logging middleware async function* clientLoggingMiddleware( call: ClientMiddlewareCall, options: CallOptions, ) { console.log(`[client] ${call.method.path} →`); try { const result = yield* call.next(call.request, options); console.log(`[client] ${call.method.path} ← OK`); return result; } catch (err) { if (err instanceof ClientError) { console.error(`[client] ${call.method.path} ← ${Status[err.code]}: ${err.details}`); } else if (isAbortError(err)) { console.warn(`[client] ${call.method.path} cancelled`); } throw err; } } const client: ExampleServiceClient = createClientFactory() .use(clientLoggingMiddleware) .create(ExampleServiceDefinition, channel); // --- Unary call with metadata and cancellation --- const abortController = new AbortController(); setTimeout(() => abortController.abort(), 10_000); try { const response = await client.exampleUnaryMethod( {id: '42'}, { metadata: Metadata({'x-trace-id': 'abc-123'}, signal: abortController.signal, onHeader: h => console.log('header:', h.get('x-server-id')), onTrailer: t => console.log('trailer:', t.get('x-duration-ms')), }, ); console.log(response.result); // "Hello, 42" } catch (err) { if (err instanceof ClientError && err.code === Status.NOT_FOUND) { console.warn('Not found'); } else { throw err; } } // --- Server streaming call --- for await (const item of client.exampleStreamingMethod({id: '1'})) { console.log(item.result); } // --- Client streaming call --- async function* requests(): AsyncIterable> { for (const id of ['a', 'b', 'c']) yield {id}; } const batchResponse = await client.exampleClientStreamingMethod(requests()); // --- Default call options per method --- const clientWithDefaults = createClientFactory().create(ExampleServiceDefinition, channel, { '*': {signal: abortController.signal}, // apply to all methods exampleUnaryMethod: {metadata: Metadata({'x-priority': 'high'})}, // per method }); channel.close(); ``` -------------------------------- ### Generate Server Reflection Descriptor Set Source: https://context7.com/deeplay-io/nice-grpc/llms.txt Generates a descriptor set file required for nice-grpc-server-reflection. This includes all imported proto files. ```bash ./node_modules/.bin/grpc_tools_node_protoc \ --descriptor_set_out=protoset.bin --include_imports \ --proto_path=./proto ./proto/example.proto ``` -------------------------------- ### Attach Server Middleware Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-prometheus/README.md Attach the prometheusServerMiddleware as the first middleware on your nice-grpc server to collect server-side metrics. ```typescript import {createServer} from 'nice-grpc'; import {prometheusServerMiddleware} from 'nice-grpc-prometheus'; const server = createServer() .use(prometheusServerMiddleware()) .use(/* ... other middleware */); ``` -------------------------------- ### `createChannel` / `createClient` (Browser) Source: https://context7.com/deeplay-io/nice-grpc/llms.txt Browser client with the same API as the Node.js client. Uses `FetchTransport` by default; `WebsocketTransport` available for full-duplex streaming via `grpcwebproxy`. ```APIDOC ## `createChannel` / `createClient` (Browser) ### Description Browser client with the same API as the Node.js client. Uses `FetchTransport` by default; `WebsocketTransport` available for full-duplex streaming via `grpcwebproxy`. ### Usage ```ts import { createChannel, createClient, createClientFactory, FetchTransport, WebsocketTransport, ClientError, Status, Metadata, } from 'nice-grpc-web'; import {ExampleServiceDefinition} from './compiled_proto/example'; // Default fetch transport const channel = createChannel('https://api.example.com'); // Explicit fetch transport (equivalent) const fetchChannel = createChannel('https://api.example.com', FetchTransport()); // WebSocket transport (requires grpcwebproxy, enables full-duplex) const wsChannel = createChannel('https://api.example.com', WebsocketTransport()); const client = createClient(ExampleServiceDefinition, channel); // Unary call const res = await client.exampleUnaryMethod({id: 'user-1'}, { metadata: Metadata({'Authorization': 'Bearer '}), onHeader: h => console.log('response header:', h), }); // Server streaming for await (const msg of client.exampleStreamingMethod({id: 'feed-1'})) { console.log('received:', msg.result); } ``` ``` -------------------------------- ### `createChannel` / `createClient` (Node.js) Source: https://context7.com/deeplay-io/nice-grpc/llms.txt Creates an insecure or TLS channel and a typed client stub. Client methods return Promises (unary/client-streaming) or Async Iterables (server-streaming/bidi-streaming). ```APIDOC ## `createChannel` / `createClient` (Node.js) ### Description Creates an insecure or TLS channel and a typed client stub. Client methods return Promises (unary/client-streaming) or Async Iterables (server-streaming/bidi-streaming). ### Usage ```ts import { createChannel, createClient, createClientFactory, ChannelCredentials, ClientError, ClientMiddlewareCall, CallOptions, Metadata, Status, waitForChannelReady, } from 'nice-grpc'; import {isAbortError} from 'abort-controller-x'; import { ExampleServiceDefinition, ExampleServiceClient, ExampleRequest, DeepPartial, } from './compiled_proto/example'; // Insecure channel (all equivalent) const channel = createChannel('localhost:50051'); // TLS channel const tlsChannel = createChannel('https://api.example.com'); // Explicit credentials const mtlsChannel = createChannel('api.example.com:443', ChannelCredentials.createSsl()); // Wait for channel readiness before first call (optional) await waitForChannelReady(channel, new Date(Date.now() + 5_000)); // Client logging middleware async function* clientLoggingMiddleware( call: ClientMiddlewareCall, options: CallOptions, ) { console.log(`[client] ${call.method.path} →`); try { const result = yield* call.next(call.request, options); console.log(`[client] ${call.method.path} ← OK`); return result; } catch (err) { if (err instanceof ClientError) { console.error(`[client] ${call.method.path} ← ${Status[err.code]}: ${err.details}`); } else if (isAbortError(err)) { console.warn(`[client] ${call.method.path} cancelled`); } throw err; } } const client: ExampleServiceClient = createClientFactory() .use(clientLoggingMiddleware) .create(ExampleServiceDefinition, channel); // --- Unary call with metadata and cancellation --- const abortController = new AbortController(); setTimeout(() => abortController.abort(), 10_000); try { const response = await client.exampleUnaryMethod( {id: '42'}, { metadata: Metadata({'x-trace-id': 'abc-123'}, signal: abortController.signal, onHeader: h => console.log('header:', h.get('x-server-id')), onTrailer: t => console.log('trailer:', t.get('x-duration-ms')), }, ); console.log(response.result); // "Hello, 42" } catch (err) { if (err instanceof ClientError && err.code === Status.NOT_FOUND) { console.warn('Not found'); } else { throw err; } } // --- Server streaming call --- for await (const item of client.exampleStreamingMethod({id: '1'})) { console.log(item.result); } // --- Client streaming call --- async function* requests(): AsyncIterable> { for (const id of ['a', 'b', 'c']) yield {id}; } const batchResponse = await client.exampleClientStreamingMethod(requests()); // --- Default call options per method --- const clientWithDefaults = createClientFactory().create(ExampleServiceDefinition, channel, { '*': {signal: abortController.signal}, // apply to all methods exampleUnaryMethod: {metadata: Metadata({'x-priority': 'high'})}, // per method }); channel.close(); ``` ``` -------------------------------- ### Compile Protobuf with ts-proto (Windows) Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-web/README.md When running on a Windows command line, wrap the ts_proto_opt value with double quotes. ```bash --ts_proto_opt="outputServices=nice-grpc,outputServices=generic-definitions,useExactTypes=false" ``` -------------------------------- ### Channels Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-web/README.md Explains how to create a channel for establishing communication with a gRPC server. It covers specifying the address and optional transports like FetchTransport, WebsocketTransport, and NodeHttpTransport. ```APIDOC ## Channels A channel is constructed from an address and optional transport. The following are equivalent: ```ts import {createChannel, FetchTransport} from 'nice-grpc-web'; createChannel('https://example.com:8080'); createChannel('https://example.com:8080', FetchTransport()); ``` If the port is omitted, it defaults to `80` for `http`, and `443` for `https`. A non-standard `WebsocketTransport` is also available, that only works with [improbable-eng grpcwebproxy](https://github.com/improbable-eng/grpc-web/tree/master/go/grpcwebproxy) and allows to overcome some limitations (see [Compatibility](#compatibility)). It is still recommended to use `FetchTransport` whenever possible. To support older NodeJS versions, we also provide `NodeHttpTransport` which is based on `http` and `https` modules (see [Compatibility](#compatibility)). ``` -------------------------------- ### Basic Usage of DevTools Middleware Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-client-middleware-devtools/README.md Integrate the devtoolsLoggingMiddleware into your nice-grpc client factory to enable request and response visibility in the browser extension. Ensure the 'address' variable is correctly defined for your gRPC service. ```typescript import { createClientFactory, createChannel, ClientError, Status, } from 'nice-grpc'; import {devtoolsLoggingMiddleware} from 'nice-grpc-client-middleware-devtools'; const clientFactory = createClientFactory().use(devtoolsLoggingMiddlware); const channel = createChannel(address); const client = clientFactory.create(ExampleService, channel); const response = await client.exampleMethod(request); // The request and response will be visible in the Browser extension ``` -------------------------------- ### Attach Client Middleware Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-prometheus/README.md Attach the prometheusClientMiddleware as the first middleware on your nice-grpc client factory to collect client-side metrics. ```typescript import {createClientFactory} from 'nice-grpc'; import {prometheusClientMiddleware} from 'nice-grpc-prometheus'; const clientFactory = createClientFactory() .use(prometheusClientMiddleware()) .use(/* ... other middleware */); const client = clientFactory.create(/* ... */); ``` -------------------------------- ### OpenTelemetry Server and Client Middleware with nice-grpc Source: https://context7.com/deeplay-io/nice-grpc/llms.txt Integrate OpenTelemetry for distributed tracing by attaching `openTelemetryServerMiddleware` to the server and `openTelemetryClientMiddleware` to the client factory. Configure OpenTelemetry provider and span processors before applying the middleware. The middleware automatically adds standard RPC span attributes. ```typescript import {createServer, createClientFactory} from 'nice-grpc'; import { openTelemetryServerMiddleware, openTelemetryClientMiddleware, } from 'nice-grpc-opentelemetry'; import {NodeTracerProvider} from '@opentelemetry/sdk-trace-node'; import {SimpleSpanProcessor, ConsoleSpanExporter} from '@opentelemetry/sdk-trace-base'; import {registerInstrumentations} from '@opentelemetry/instrumentation'; // Configure OpenTelemetry (use your own exporter in production) const provider = new NodeTracerProvider(); provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); provider.register(); // ─── Server ─────────────────────────────────────────────────────────────── // Must be first middleware so it wraps the entire call const server = createServer() .use(openTelemetryServerMiddleware()) .use(/* ... other middleware */); server.add(ExampleServiceDefinition, exampleServiceImpl); await server.listen('0.0.0.0:50051'); ``` ```typescript // ─── Client ─────────────────────────────────────────────────────────────── // Also attach first on the client factory const clientFactory = createClientFactory() .use(openTelemetryClientMiddleware()) .use(/* ... other middleware */); const client = clientFactory.create(ExampleServiceDefinition, createChannel('localhost:50051')); // Each call will generate a span with attributes: // rpc.system = "grpc" // rpc.service = "nice_grpc.example.ExampleService" // rpc.method = "ExampleUnaryMethod" // rpc.grpc.status_code = 0 // rpc.grpc.status_text = "OK" await client.exampleUnaryMethod({id: '1'}); ``` -------------------------------- ### Client Middleware Options for nice-grpc-prometheus Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-prometheus/README.md Configuration options for the Prometheus client middleware. These allow you to provide custom metric instances for various stages of the client call lifecycle. ```ts { clientStartedMetric?: Counter; // labelNames: labelNames clientHandledMetric?: Counter; // labelNames: labelNamesWithCode clientStreamMsgReceivedMetric?: Counter; // labelNames: labelNames clientStreamMsgSentMetric?: Counter; // labelNames: labelNames clientHandlingSecondsMetric?: Histogram; // labelNames: labelNamesWithCode } ``` -------------------------------- ### Generate JS and TS code with google-protobuf Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc/README.md Use grpc_tools_node_protoc with google-protobuf plugins to generate JavaScript and TypeScript definitions for gRPC services. ```bash ./node_modules/.bin/grpc_tools_node_protoc \ --plugin=protoc-gen-grpc=./node_modules/.bin/grpc_tools_node_protoc_plugin \ --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts \ --js_out=import_style=commonjs,binary:./compiled_proto \ --ts_out=grpc_js:./compiled_proto \ --grpc_out=grpc_js:./compiled_proto \ --proto_path=./proto \ ./proto/example.proto ``` -------------------------------- ### Attach Terminator Middleware and Terminate Server Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-server-middleware-terminator/README.md Instantiate the terminator middleware, attach it to the nice-grpc server, and call `terminate()` before initiating server shutdown. ```typescript import {createServer} from 'nice-grpc'; import {TerminatorMiddleware} from 'nice-grpc-server-middleware-terminator'; import {ExampleServiceDefinition} from './compiled_proto/example'; const terminatorMiddleware = TerminatorMiddleware(); const server = createServer().use(terminatorMiddleware); server.add(ExampleServiceDefinition, exampleServiceImpl); await server.listen('0.0.0.0:8080'); // ... terminate middleware before shutdown: terminatorMiddleware.terminate(); await server.shutdown(); ``` -------------------------------- ### Create Browser gRPC Channel and Client (nice-grpc-web) Source: https://context7.com/deeplay-io/nice-grpc/llms.txt Use `createChannel` with `FetchTransport` or `WebsocketTransport` for browser-based gRPC calls. The API mirrors the Node.js client. `WebsocketTransport` enables full-duplex streaming via `grpcwebproxy`. ```typescript import { createChannel, createClient, createClientFactory, FetchTransport, WebsocketTransport, ClientError, Status, Metadata, } from 'nice-grpc-web'; import {ExampleServiceDefinition} from './compiled_proto/example'; // Default fetch transport const channel = createChannel('https://api.example.com'); // Explicit fetch transport (equivalent) const fetchChannel = createChannel('https://api.example.com', FetchTransport()); // WebSocket transport (requires grpcwebproxy, enables full-duplex) const wsChannel = createChannel('https://api.example.com', WebsocketTransport()); const client = createClient(ExampleServiceDefinition, channel); // Unary call const res = await client.exampleUnaryMethod({id: 'user-1'}, { metadata: Metadata({'Authorization': 'Bearer '}), onHeader: h => console.log('response header:', h), }); // Server streaming for await (const msg of client.exampleStreamingMethod({id: 'feed-1'})) { console.log('received:', msg.result); } ``` -------------------------------- ### Attaching Middleware to Server Source: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc/README.md Attach middleware to a server instance using the `server.use()` method. Each `use()` call returns a new server instance with the middleware applied. ```typescript const server = createServer().use(middleware1).use(middleware2); ```