Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/moveaxlab/nestjs-grpc-client
A dataloader implementation to talk with gRPC servers, with support for request merging and cross-request caching.
https://github.com/moveaxlab/nestjs-grpc-client
dataloader graphql grpc nestjs
Last synced: about 2 months ago
JSON representation
A dataloader implementation to talk with gRPC servers, with support for request merging and cross-request caching.
- Host: GitHub
- URL: https://github.com/moveaxlab/nestjs-grpc-client
- Owner: moveaxlab
- License: mit
- Created: 2023-05-24T09:26:40.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2024-03-06T14:59:27.000Z (10 months ago)
- Last Synced: 2024-11-15T04:11:13.341Z (about 2 months ago)
- Topics: dataloader, graphql, grpc, nestjs
- Language: TypeScript
- Homepage:
- Size: 387 KB
- Stars: 2
- Watchers: 3
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# NestJS gRPC Client
![NPM](https://img.shields.io/npm/l/%40moveaxlab%2Fgraphql-client)
[![npm](https://img.shields.io/npm/v/@moveaxlab/nestjs-grpc-client)](https://www.npmjs.com/package/@moveaxlab/nestjs-grpc-client)
![Static Badge](https://img.shields.io/badge/node_version-_%3E%3D20-green)This library defines gRPC dataloaders you can inject dynamically in GraphQL resolvers in order to optimize calls via batching and caching.
More about the dataloader pattern at https://github.com/graphql/dataloader
## Installation
```bash
yarn add @moveaxlab/nestjs-grpc-client
```## Usage
### Dataloaders
gRPC dataloaders are based on gRPC clients defined as follows:
```typescript
// package.client.ts
import { GrpcClientForService } from '@moveax/nestjs-grpc-client';
import { grpcPkg } from 'somewhere'; // import also your autogenerated gRPC packageexport type PackageClient = GrpcClientForService<
grpcPkg.PackageServiceDefinition
>;
// OR
export type PackageClientWithStreamingMethods = GrpcClientForService<
grpcPkg.PackageServiceDefinition,
'myClientStreamingMethod' | 'myBidirectionalStreamingMethod'
>;
```Implement your gRPC dataloader:
```typescript
// package.dataloader.ts
import { Metadata } from '@grpc/grpc-js';
import { GrpcDataLoaderProvider, DataLoaderForClient, Request, createDataLoaderDecorator } from '@moveax/nestjs-grpc-client';
import { Injectable, Logger } from '@nestjs/common';
import { PackageClient } from 'package.client';
import { grpcPkg } from 'somewhere'; // import also your autogenerated gRPC package@Injectable()
export class PackageDataLoaderProvider extends GrpcDataLoaderProvider {
client: PackageClient;
logger = new Logger(PackageDataLoaderProvider.name);createMetadata(_: Request): Metadata {
const metadata = new Metadata();
// you can use the Express' request token to authenticate also the gRPC call
metadata.set('authorization', req.get('authorization'));
return metadata;
}get cacheConfig() {
return {
someMethod: {
cacheKeyFn: (request: grpcPkg.ISomeMethodRequest) => {
return `pkgService.someMethod:${input.param1}-${input.param2}`;
},
ttl: 60,
},
};
}
}export const PackageService = createDataLoaderDecorator(PackageDataLoaderProvider.prototype);
export type PackageDataloader = DataLoaderForClient;
```1. The `cacheConfig` getter returns an object containing cache configuration for the various methods.
If a method needs to be cached, the `cacheConfig` must contain an entry for that method that takes in input
the method request and returns a string, which will be used as the cache key. A TTL can be specified,
that will be used if global caching is enabled (see below).
2. The `PackageService` is an object containing a parameter decorator for each method of the gRPC client.
You can use the decorator in your resolvers to obtain an instance of the dataloader (see below).
3. The `PackageDataloader` is a type containing the types of each method dataloader.
You can use the type in your resolvers to add type safety to your loaders.Add the `GrpcDataLoaderInterceptor` to your app in order to load dataloaders relevant for the request at runtime:
```typescript
import { Module } from '@nestjs/common';
import { APP_INTERCEPTOR } from '@nestjs/core';
import { GrpcDataLoaderInterceptor } from '@moveax/nestjs-grpc-client';@Module({
provides: [
{
provide: APP_INTERCEPTOR,
useClass: GrpcDataLoaderInterceptor,
}
],
/* ... */
})
export class AppModule {}
```Now you can use the dataloader in your resolvers:
```typescript
// imports omitted for lack of will@Resolver()
class Whatever {
@Query()
async getWhatever(
@PackageService.someMethod() loader: PackageDataloader['someMethod']
) {
const response = await loader.load(/* gRPC request */);
// do whatever you want with the response now
}
}
```### Batching requests
To batch several requests to a given service when doing API composition,
specify the `mergeConfig` inside your dataloader provider.The `mergeConfig` provides two properties for each endpoint:
- `mergeInput`, that takes an array of requests and combines them to a single request
- `splitOutput`, that takes the original array of requests and a single response,
and splits it into an array of responses### Global caching
To use global caching, pass `true` to the loader decorator:
```typescript
// imports omitted for lack of will@Resolver()
class Whatever {
@Query()
async getWhatever(
@PackageService.someMethod(true) loader: PackageDataloader['someMethod']
) {
const response = await loader.load(/* gRPC request */);
// do whatever you want with the response now
}
}
```The `ttl` must be set to something greater than 0 inside the cacheConfig
for the dataloader, for global caching to work. _The TTL is expressed in seconds._All requests to that specific dataloader will be cached for `ttl` seconds,
in a cache shared between all calls. __Use global caching with care:__ the global cache will skip all authorization logic
that may live inside your backend services.