nice-grpc DevTools Client Middleware
raw JSON →This package provides a client-side middleware for `nice-grpc` and `nice-grpc-web` that integrates with the `grpc-web-devtools` browser extension. Its primary function is to log gRPC-Web requests and responses, making them visible and inspectable within the browser's developer tools. This is crucial for debugging frontend applications that communicate with gRPC backends via gRPC-Web, a common pain point due to gRPC-Web's protocol translation layer. Currently at version 1.0.10, the package generally follows the active development and release cadence of its parent `nice-grpc` project, which sees frequent updates. It offers a straightforward way to gain visibility into gRPC-Web traffic, differentiating itself by specifically targeting the popular `grpc-web-devtools` extension for an enhanced developer experience.
Common errors
error ReferenceError: require is not defined ↓
import statements: import { devtoolsClientMiddleware } from 'nice-grpc-client-middleware-devtools'; error TypeError: Cannot read properties of undefined (reading 'use') ↓
createClientFactory from nice-grpc-web and call createClientFactory() before chaining .use() calls: const clientFactory = createClientFactory().use(middleware); error gRPC-Web calls not appearing in browser's Network tab or grpc-web-devtools extension. ↓
grpc-web-devtools extension is installed and enabled. Double-check that devtoolsClientMiddleware is applied to your createClientFactory() instance. Ensure your browser is indeed making gRPC-Web requests (often visible as POST requests to /Service/Method with Content-Type: application/grpc-web+proto or application/grpc-web-text). Warnings
gotcha This middleware is designed to work with the `grpc-web-devtools` browser extension. Requests will not appear in browser DevTools unless the extension is installed and active. ↓
gotcha The `nice-grpc` middleware chain processes in reverse order of attachment: `clientFactory.use(middleware1).use(middleware2)` means `middleware1` is invoked last, and `middleware2` is invoked first. Consider middleware order carefully if you have multiple middlewares. ↓
gotcha This middleware is primarily intended for `nice-grpc-web` clients running in the browser. While technically usable with `nice-grpc` in Node.js, it won't provide benefits for browser-based debugging there and might lead to confusion. ↓
Install
npm install nice-grpc-client-middleware-devtools yarn add nice-grpc-client-middleware-devtools pnpm add nice-grpc-client-middleware-devtools Imports
- devtoolsClientMiddleware wrong
const { devtoolsClientMiddleware } = require('nice-grpc-client-middleware-devtools');correctimport { devtoolsClientMiddleware } from 'nice-grpc-client-middleware-devtools'; - devtoolsUnaryLoggingMiddleware
import { devtoolsUnaryLoggingMiddleware } from 'nice-grpc-client-middleware-devtools'; - devtoolsStreamLoggingMiddleware
import { devtoolsStreamLoggingMiddleware } from 'nice-grpc-client-middleware-devtools';
Quickstart
import { createClientFactory, createChannel, ClientError, Status } from 'nice-grpc-web';
import { devtoolsClientMiddleware } from 'nice-grpc-client-middleware-devtools';
import { type ExampleServiceDefinition, ExampleServiceDefinition } from './compiled_proto/example';
// Imagine your compiled Protobuf types look like this (e.g., from ts-proto)
interface ExampleServiceDefinition {
readonly methodName: string;
readonly requestType: any;
readonly responseType: any;
// ... other protobuf definitions
}
// 1. Define your gRPC service (usually compiled from .proto)
// ExampleServiceDefinition would come from your proto compilation output
// 2. Create a gRPC-Web channel pointing to your proxy/server
const channel = createChannel('http://localhost:8080');
// 3. Create a client factory and apply the devtools middleware
const clientFactory = createClientFactory()
.use(devtoolsClientMiddleware);
// 4. Create your gRPC client instance
const client = clientFactory.create(
ExampleServiceDefinition,
channel,
);
// 5. Make a gRPC call (this will now be logged in grpc-web-devtools)
async function callService() {
try {
console.log('Making a gRPC call...');
const response = await client.exampleMethod({ name: 'World' }, {
metadata: { 'x-request-id': '123' },
// Additional call options can be passed here
});
console.log('gRPC response:', response);
} catch (error: unknown) {
if (error instanceof ClientError) {
console.error(`gRPC Error: ${error.code} - ${error.details}`);
} else {
console.error('Unknown error:', error);
}
}
}
callService();
// A minimal example for ExampleServiceDefinition if not using ts-proto directly:
export const ExampleServiceDefinition = {
methodName: 'ExampleService',
requestType: {}, // Define your request type structure
responseType: {}, // Define your response type structure
// Typically, this comes from compiled .proto files
methods: {
exampleMethod: {},
}
} as unknown as ExampleServiceDefinition;