# @probitas/client-grpc > Version: 0.6.0 gRPC client for [Probitas](https://github.com/probitas-test/probitas) scenario testing framework. This package provides a gRPC client with Server Reflection support, designed for integration testing of gRPC services. It is a thin wrapper around [`@probitas/client-connectrpc`](https://jsr.io/@probitas/client-connectrpc) with `protocol: "grpc"` pre-configured. ## Features - **Native gRPC**: Uses gRPC protocol (HTTP/2 with binary protobuf) - **Server Reflection**: Auto-discover services and methods at runtime - **Field Name Conversion**: Automatic snake_case ↔ camelCase conversion - **TLS Support**: Configure secure connections with custom certificates - **Duration Tracking**: Built-in timing for performance monitoring - **Error Handling**: Test error responses without throwing exceptions - **Resource Management**: Implements `AsyncDisposable` for proper cleanup ## Installation ```bash deno add jsr:@probitas/client-grpc ``` ## Quick Start ```ts import { createGrpcClient } from "@probitas/client-grpc"; // Create client (uses reflection by default) const client = createGrpcClient({ url: "http://localhost:50051", }); // Call a method const response = await client.call( "echo.EchoService", "echo", { message: "Hello!" } ); console.log(response.data); await client.close(); ``` ## Service Discovery ```ts import { createGrpcClient } from "@probitas/client-grpc"; const client = createGrpcClient({ url: "http://localhost:50051" }); // Discover available services const services = await client.reflection.listServices(); console.log("Services:", services); // Get method information const info = await client.reflection.getServiceInfo("echo.EchoService"); console.log("Methods:", info.methods); await client.close(); ``` ## Field Name Conventions The client automatically handles field name conversion between protobuf and JavaScript: - **Request**: Accept both `snake_case` (protobuf) and `camelCase` (JavaScript) field names - **Response**: - `response.data` — Plain JSON with `camelCase` fields (no `$typeName`) - `response.raw` — Original protobuf Message with metadata (includes `$typeName`) ```ts import { createGrpcClient } from "@probitas/client-grpc"; const client = createGrpcClient({ url: "http://localhost:50051" }); // Request: Both camelCase and snake_case work const response = await client.call("echo.Echo", "echoWithDelay", { message: "hello", delayMs: 100, // camelCase (recommended for JavaScript) // delay_ms: 100, // snake_case (protobuf style) also works }); // Response data: JSON with camelCase fields console.log(response.data); // { message: "hello", metadata: {...} } ← no $typeName // Response raw: protobuf Message with metadata console.log(response.raw); // { $typeName: "echo.EchoResponse", message: "hello", ... } await client.close(); ``` ## Using with `using` Statement ```ts import { createGrpcClient } from "@probitas/client-grpc"; await using client = createGrpcClient({ url: "http://localhost:50051" }); const res = await client.call("echo.EchoService", "echo", { message: "test" }); console.log(res.data); // Client automatically closed when block exits ``` ## Related Packages | Package | Description | |---------|-------------| | [`@probitas/client`](https://jsr.io/@probitas/client) | Core utilities and types | | [`@probitas/client-connectrpc`](https://jsr.io/@probitas/client-connectrpc) | ConnectRPC client (supports Connect, gRPC, gRPC-Web) | ## Links - [GitHub Repository](https://github.com/probitas-test/probitas-client) - [Probitas Framework](https://github.com/probitas-test/probitas) - [gRPC](https://grpc.io/) ## Classes ### `GrpcError` ```typescript class GrpcError extends ClientError ``` Error class for ConnectRPC/gRPC errors. Use `statusCode` to distinguish between different gRPC error codes. **Constructor:** ```typescript new GrpcError( message: string, statusCode: ConnectRpcStatusCode, statusMessage: string, options?: ConnectRpcErrorOptions, ) ``` **Properties:** - [readonly] `name`: `string` - [readonly] `kind`: `"connectrpc"` - [readonly] `statusCode`: `ConnectRpcStatusCode` - [readonly] `statusMessage`: `string` - [readonly] `metadata`: `Headers | null` - [readonly] `details`: `readonly ErrorDetail[]` --- ### `GrpcNetworkError` ```typescript class GrpcNetworkError extends ClientError ``` Error thrown when a network-level failure occurs. This error indicates that the request could not be processed by the server due to network issues (connection refused, DNS resolution failure, timeout, etc.). Unlike ConnectRpcError, this error means the server was never reached. **Constructor:** ```typescript new GrpcNetworkError(message: string, options?: ErrorOptions) ``` **Properties:** - [readonly] `name`: `string` - [readonly] `kind`: `"connectrpc"` --- ## Interfaces ### `GrpcClient` ```typescript interface GrpcClient extends AsyncDisposable ``` ConnectRPC client interface. ## Field Name Conventions This client automatically handles field name conversion between protobuf and JavaScript: - **Request fields**: Accept both `snake_case` (protobuf style) and `camelCase` (JavaScript style) - **Response fields**: Converted to JavaScript conventions based on response type: - `response.data`: Plain JSON object with `camelCase` field names (no `$typeName`) - `response.raw`: Original protobuf Message object with all metadata (includes `$typeName`) **Properties:** - [readonly] `config`: `ConnectRpcClientConfig` — Client configuration - [readonly] `reflection`: `ReflectionApi` — Reflection API (only available when schema: "reflection") **Methods:** ```typescript call( serviceName: string, methodName: string, request: TRequest, options?: ConnectRpcOptions, ): Promise ``` Make a unary RPC call. ```typescript serverStream( serviceName: string, methodName: string, request: TRequest, options?: ConnectRpcOptions, ): AsyncIterable ``` Make a server streaming RPC call. ```typescript clientStream( serviceName: string, methodName: string, requests: AsyncIterable, options?: ConnectRpcOptions, ): Promise ``` Make a client streaming RPC call. ```typescript bidiStream( serviceName: string, methodName: string, requests: AsyncIterable, options?: ConnectRpcOptions, ): AsyncIterable ``` Make a bidirectional streaming RPC call. ```typescript close(): Promise ``` Close the client connection. **Example:** ```ts const client = createConnectRpcClient({ url: "http://localhost:50051" }); // Request: Both formats work await client.call("echo.Echo", "echoWithDelay", { message: "hello", delayMs: 100, // camelCase (recommended) // delay_ms: 100, // snake_case also works }); // Response: data is JSON, raw is protobuf Message const response = await client.call("echo.Echo", "echo", { message: "test" }); console.log(response.data); // { message: "test", metadata: {...} } console.log(response.raw); // { $typeName: "echo.EchoResponse", message: "test", ... } ``` --- ### `GrpcErrorOptions` ```typescript interface GrpcErrorOptions extends ErrorOptions ``` Options for ConnectRpcError construction. **Properties:** - [readonly] `metadata?`: `Headers | null` — Headers/metadata from the ConnectRPC response. - [readonly] `details?`: `readonly ErrorDetail[] | null` — Rich error details from google.rpc.Status. --- ### `GrpcOptions` ```typescript interface GrpcOptions extends CommonOptions ``` Options for individual ConnectRPC calls. **Properties:** - [readonly] `metadata?`: `HeadersInit` — Metadata to send with the request. - [readonly] `throwOnError?`: `boolean` — Whether to throw ConnectRpcError on non-OK responses (code !== 0) or failures. Overrides ConnectRpcClientConfig.throwOnError. --- ### `GrpcResponseError` ```typescript interface GrpcResponseError extends ConnectRpcResponseBase ``` ConnectRPC response with gRPC error (statusCode !== 0). The server processed the request but returned an error status. **Properties:** - [readonly] `processed`: `true` - [readonly] `ok`: `false` - [readonly] `error`: `ConnectRpcError` - [readonly] `statusCode`: `ConnectRpcStatusCode` — gRPC status code (1-16). - [readonly] `statusMessage`: `string` — Status message describing the error. - [readonly] `headers`: `Headers` — Response headers. - [readonly] `trailers`: `Headers` — Response trailers (sent at end of RPC). - [readonly] `raw`: `ConnectError` — Raw ConnectError. - [readonly] `data`: `null` — No data for error responses. --- ### `GrpcResponseFailure` ```typescript interface GrpcResponseFailure extends ConnectRpcResponseBase ``` Failed ConnectRPC request (network error, connection refused, etc.). The request did not reach gRPC processing. **Properties:** - [readonly] `processed`: `false` - [readonly] `ok`: `false` - [readonly] `error`: `ConnectRpcFailureError` - [readonly] `statusCode`: `null` — Status code (null for network failures). - [readonly] `statusMessage`: `null` — Status message (null for network failures). - [readonly] `headers`: `null` — Response headers (null for failures). - [readonly] `trailers`: `null` — Response trailers (null for failures). - [readonly] `raw`: `null` — No raw response (request didn't reach server). - [readonly] `data`: `null` — No data (request didn't reach server). --- ### `GrpcResponseSuccess` ```typescript interface GrpcResponseSuccess extends ConnectRpcResponseBase ``` Successful ConnectRPC response (statusCode === 0). **Properties:** - [readonly] `processed`: `true` - [readonly] `ok`: `true` - [readonly] `error`: `null` - [readonly] `statusCode`: `0` — gRPC status code (always 0 for success). - [readonly] `statusMessage`: `null` — Status message (null for successful responses). - [readonly] `headers`: `Headers` — Response headers. - [readonly] `trailers`: `Headers` — Response trailers (sent at end of RPC). - [readonly] `raw`: `unknown` — Raw protobuf Message object. - [readonly] `data`: `T | null` — Response data as plain JavaScript object (JSON representation). --- ### `ErrorDetail` ```typescript interface ErrorDetail ``` Rich error detail from google.rpc.Status. ConnectRPC errors can include structured details encoded in error responses. These details follow the google.protobuf.Any format with a type URL and value. **Properties:** - [readonly] `typeUrl`: `string` — Type URL identifying the error detail type. Common types include: - "type.googleapis.com/google.rpc.BadRequest" - "type.googleapis.com/google.rpc.DebugInfo" - "type.googleapis.com/google.rpc.RetryInfo" - "type.googleapis.com/google.rpc.QuotaFailure" - [readonly] `value`: `unknown` — Decoded error detail value. The structure depends on the typeUrl. --- ### `MethodInfo` ```typescript interface MethodInfo ``` Method information from reflection. **Properties:** - [readonly] `name`: `string` — Method name (e.g., "Echo") - [readonly] `localName`: `string` — Local name (camelCase) - [readonly] `kind`: `"unary" | "server_streaming" | "client_streaming" | "bidi_streaming"` — Method kind - [readonly] `inputType`: `string` — Input message type name - [readonly] `outputType`: `string` — Output message type name - [readonly] `idempotent`: `boolean` — Whether the method is idempotent --- ### `ReflectionApi` ```typescript interface ReflectionApi ``` Reflection API for ConnectRPC client. Only available when client is created with schema: "reflection". **Properties:** - [readonly] `enabled`: `boolean` — Check if reflection is enabled. **Methods:** ```typescript listServices(): Promise ``` List all available services on the server. ```typescript getServiceInfo(serviceName: string): Promise ``` Get detailed information about a specific service. ```typescript listMethods(serviceName: string): Promise ``` Get methods for a specific service. ```typescript hasService(serviceName: string): Promise ``` Check if a service exists. --- ### `ServiceDetail` ```typescript interface ServiceDetail ``` Detailed service information. **Properties:** - [readonly] `name`: `string` — Service name - [readonly] `fullName`: `string` — Fully qualified service name - [readonly] `packageName`: `string` — Package name - [readonly] `protoFile`: `string` — Proto file name - [readonly] `methods`: `readonly MethodInfo[]` — All methods --- ### `ServiceInfo` ```typescript interface ServiceInfo ``` Service information from reflection. **Properties:** - [readonly] `name`: `string` — Fully qualified service name (e.g., "echo.EchoService") - [readonly] `file`: `string` — Proto file name --- ### `TlsConfig` ```typescript interface TlsConfig ``` TLS configuration for ConnectRPC connections. **Properties:** - [readonly] `rootCerts?`: `Uint8Array` — Root CA certificate (PEM format). - [readonly] `clientCert?`: `Uint8Array` — Client certificate (PEM format). - [readonly] `clientKey?`: `Uint8Array` — Client private key (PEM format). - [readonly] `insecure?`: `boolean` — Skip server certificate verification (use only for testing). --- ### `GrpcClientConfig` ```typescript interface GrpcClientConfig extends Omit ``` Configuration for creating a gRPC client. This is a subset of ConnectRpcClientConfig with protocol fixed to "grpc". --- ## Functions ### `getGrpcStatusName` ```typescript function getGrpcStatusName(code: ConnectRpcStatusCode): string ``` Get the name of a ConnectRPC/gRPC status code. **Parameters:** - `code`: `ConnectRpcStatusCode` **Returns:** `string` **Example:** ```typescript getStatusName(0); // "OK" getStatusName(5); // "NOT_FOUND" getStatusName(16); // "UNAUTHENTICATED" ``` --- ### `isGrpcStatusCode` ```typescript function isGrpcStatusCode(code: number): code is ConnectRpcStatusCode ``` Check if a number is a valid ConnectRPC/gRPC status code. **Parameters:** - `code`: `number` **Returns:** `code is ConnectRpcStatusCode` **Example:** ```typescript isConnectRpcStatusCode(0); // true isConnectRpcStatusCode(16); // true isConnectRpcStatusCode(99); // false ``` --- ### `createGrpcClient` ```typescript function createGrpcClient(config: GrpcClientConfig): ConnectRpcClient ``` Create a new gRPC client instance. This is a thin wrapper around `createConnectRpcClient` with `protocol: "grpc"` fixed. The client provides Server Reflection support for runtime service discovery. **Parameters:** - `config`: `GrpcClientConfig` — - Client configuration including server address **Returns:** `ConnectRpcClient` A new gRPC client instance **Example:** Basic usage with reflection ```ts import { createGrpcClient } from "@probitas/client-grpc"; const client = createGrpcClient({ url: "http://localhost:50051", }); // Call a method const response = await client.call( "echo.EchoService", "echo", { message: "Hello!" } ); console.log(response.data); await client.close(); ``` Service discovery with reflection ```ts import { createGrpcClient } from "@probitas/client-grpc"; const client = createGrpcClient({ url: "http://localhost:50051", }); // Discover available services const services = await client.reflection.listServices(); console.log("Available services:", services); // Get method information const info = await client.reflection.getServiceInfo("echo.EchoService"); console.log("Methods:", info.methods); await client.close(); ``` Testing error responses ```ts import { createGrpcClient } from "@probitas/client-grpc"; const client = createGrpcClient({ url: "http://localhost:50051" }); const response = await client.call( "user.UserService", "getUser", { id: "non-existent" }, { throwOnError: false } ); if (!response.ok) { console.log("Error code:", response.statusCode); // NOT_FOUND = 5 } await client.close(); ``` Using `await using` for automatic cleanup ```ts import { createGrpcClient } from "@probitas/client-grpc"; await using client = createGrpcClient({ url: "http://localhost:50051", }); const res = await client.call("echo.EchoService", "echo", { message: "test" }); console.log(res.data); // Client automatically closed when scope exits ``` --- ## Types ### `GrpcResponse` ```typescript type GrpcResponse = ConnectRpcResponseSuccess | ConnectRpcResponseError | ConnectRpcResponseFailure ``` ConnectRPC response union type. Use `processed` to distinguish between server responses and failures: - `processed === true`: Server responded (Success or Error) - `processed === false`: Request failed (Failure) Use `ok` to check for success: - `ok === true`: Success (statusCode === 0) - `ok === false`: Error or Failure --- ### `GrpcStatusCode` ```typescript type GrpcStatusCode = unknown ``` ConnectRPC/gRPC status code type. Derived from ConnectRpcStatus values. --- ### `FileDescriptorSet` ```typescript type FileDescriptorSet = MessageShape ``` FileDescriptorSet message type from @bufbuild/protobuf. This is the decoded protobuf message containing file descriptors. --- ## Variables ### `GrpcStatus` ```typescript const GrpcStatus: { OK: number; CANCELLED: number; UNKNOWN: number; INVALID_ARGUMENT: number; DEADLINE_EXCEEDED: number; NOT_FOUND: number; ALREADY_EXISTS: number; PERMISSION_DENIED: number; RESOURCE_EXHAUSTED: number; FAILED_PRECONDITION: number; ABORTED: number; OUT_OF_RANGE: number; UNIMPLEMENTED: number; INTERNAL: number; UNAVAILABLE: number; DATA_LOSS: number; UNAUTHENTICATED: number; } ``` ConnectRPC/gRPC status codes. These codes are used by both gRPC and ConnectRPC protocols. --- ## Related Links ### This Package - [`ErrorDetail`](https://probitas-test.github.io/documents/api/client-grpc#ErrorDetail) - [`GrpcClientConfig`](https://probitas-test.github.io/documents/api/client-grpc#GrpcClientConfig) - [`MethodInfo`](https://probitas-test.github.io/documents/api/client-grpc#MethodInfo) - [`ReflectionApi`](https://probitas-test.github.io/documents/api/client-grpc#ReflectionApi) - [`ServiceDetail`](https://probitas-test.github.io/documents/api/client-grpc#ServiceDetail) - [`ServiceInfo`](https://probitas-test.github.io/documents/api/client-grpc#ServiceInfo) ### Other Packages - [`CommonOptions`](https://probitas-test.github.io/documents/api/client#CommonOptions) (@probitas/client) - [`ConnectRpcClient`](https://probitas-test.github.io/documents/api/expect#ConnectRpcClient) (@probitas/expect) - [`ConnectRpcClientConfig`](https://probitas-test.github.io/documents/api/expect#ConnectRpcClientConfig) (@probitas/expect) - [`ConnectRpcError`](https://probitas-test.github.io/documents/api/expect#ConnectRpcError) (@probitas/expect) - [`ConnectRpcErrorOptions`](https://probitas-test.github.io/documents/api/expect#ConnectRpcErrorOptions) (@probitas/expect) - [`ConnectRpcFailureError`](https://probitas-test.github.io/documents/api/expect#ConnectRpcFailureError) (@probitas/expect) - [`ConnectRpcOptions`](https://probitas-test.github.io/documents/api/expect#ConnectRpcOptions) (@probitas/expect) - [`ConnectRpcResponse`](https://probitas-test.github.io/documents/api/probitas#ConnectRpcResponse) (@probitas/probitas) - [`ConnectRpcResponseError`](https://probitas-test.github.io/documents/api/expect#ConnectRpcResponseError) (@probitas/expect) - [`ConnectRpcResponseFailure`](https://probitas-test.github.io/documents/api/expect#ConnectRpcResponseFailure) (@probitas/expect) - [`ConnectRpcResponseSuccess`](https://probitas-test.github.io/documents/api/expect#ConnectRpcResponseSuccess) (@probitas/expect) - [`ConnectRpcStatusCode`](https://probitas-test.github.io/documents/api/expect#ConnectRpcStatusCode) (@probitas/expect) ### Built-in Types - [`AsyncIterable`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_async_iterator_and_async_iterable_protocols) - [`Omit`](https://www.typescriptlang.org/docs/handbook/utility-types.html#omittype-keys) - [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) - [`Uint8Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) --- *Last updated: 2026-01-12*