Issue
Overview
- Working on a NestJS project with GraphQL using a laptop with Window OS
- Experimenting with GraphQL Subscriptions using
graphql-redis-subscription@2.5.0
package - Redis is used in a docker container, see the
docker-compose.yml
below - The problem arose when the subscription
postAdded
is executed in GraphQL Playground. Instead of hanging to listen for events, it had crashed before I performedcreatePost
mutation.
My code (I only include some important details)
posts.resolver.ts
import { Inject, UseGuards } from '@nestjs/common';
import { Args, Context, Mutation, Resolver, Subscription } from '@nestjs/graphql';
import { RedisPubSub } from 'graphql-redis-subscriptions';
import { GraphqlJwtAuthGuard } from '../auth/guards';
import { RequestWithUser } from '../auth/interfaces';
import { PUB_SUB } from '../pubsub/pubsub.module'
const POST_ADDED_EVENT = 'postAdded';
@Resolver(() => Post)
export class PostsResolver {
constructor(
private postsService: PostsService,
@Inject(PUB_SUB) private pubSub: RedisPubSub,
) {}
// my subscription (issue)
@Subscription(() => Post)
postAdded() {
return this.pubSub.asyncIterator(POST_ADDED_EVENT);
}
// createPost method
@Mutation(() => Post)
@UseGuards(GraphqlJwtAuthGuard)
async createPost(
@Args('input') createPostInput: CreatePostInput,
@Context() context: { req: RequestWithUser },
) {
// just create a new post (assuming it works)
const newPost = await this.postsService.create(
createPostInput,
context.req.user,
);
this.pubSub.publish(POST_ADDED_EVENT, { postAdded: newPost });
return newPost;
}
}
pubsub.module.ts
import { ConfigService } from '@nestjs/config';
import { RedisPubSub } from 'graphql-redis-subscriptions';
import { Global, Module } from '@nestjs/common';
export const PUB_SUB = 'PUB_SUB';
@Global()
@Module({
providers: [
{
provide: PUB_SUB,
useFactory: (configService: ConfigService) =>
new RedisPubSub({
connection: {
host: configService.get('REDIS_HOST'),
port: configService.get('REDIS_PORT'),
},
}),
inject: [ConfigService],
},
],
exports: [PUB_SUB],
})
export class PubSubModule {}
app.module.ts
import { PubSubModule } from './pubsub/pubsub.module';
@Module({
imports: [
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
playground: true,
autoSchemaFile: path.join(process.cwd(), 'src/schema.gql'),
installSubscriptionHandlers: true,
}),
PubSubModule,
ConfigModule.forRoot({
isGlobal: true,
validationSchema: Joi.object({
REDIS_HOST: Joi.string().required(),
REDIS_PORT: Joi.number().required()
}),
}),
],
providers: [AppService, AppResolver],
})
export class AppModule {}
version: '3'
services:
redis:
image: 'redis:alpine'
ports:
- '6379:6379'
redis-commander:
image: rediscommander/redis-commander:latest
environment:
- REDIS_HOSTS=local:redis:6379
ports:
- '8081:8081'
depends_on:
- redis
All the environment variables have already been defined in .env
file.
REDIS_HOST="localhost"
REDIS_PORT=6379
When I run yarn start:dev
and execute the subscription in GraphQL Playground
subscription {
postAdded {
id
title
paragraphs
}
}
it raises an error like this:
{
"errors": [
{
"message": "Cannot read properties of undefined (reading 'length')",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"postAdded"
]
}
]
}
The terminal that monitors NestJS also raises an error like this:
[Nest] 8080 - 07/21/2022, 9:30:24 AM ERROR [ExceptionsHandler] Cannot read properties of undefined (reading 'length')
TypeError: Cannot read properties of undefined (reading 'length')
at JavascriptRedisParser.execute (C:\Users\HP\nestjs-project\node_modules\redis-parser\lib\parser.js:530:38)
at Object.data (C:\Users\HP\nestjs-project\node_modules\ioredis\built\DataHandler.js:25:20)
at TransformOperationExecutor.transform (C:\Users\HP\nestjs-project\node_modules\src\TransformOperationExecutor.ts:207:39)
at TransformOperationExecutor.transform (C:\Users\HP\nestjs-project\node_modules\src\TransformOperationExecutor.ts:327:31)
at TransformOperationExecutor.transform (C:\Users\HP\nestjs-project\node_modules\src\TransformOperationExecutor.ts:327:31)
at TransformOperationExecutor.transform (C:\Users\HP\nestjs-project\node_modules\src\TransformOperationExecutor.ts:327:31)
at TransformOperationExecutor.transform (C:\Users\HP\nestjs-project\node_modules\src\TransformOperationExecutor.ts:327:31)
at TransformOperationExecutor.transform (C:\Users\HP\nestjs-project\node_modules\src\TransformOperationExecutor.ts:327:31)
at ClassTransformer.instanceToPlain (C:\Users\HP\nestjs-project\node_modules\src\ClassTransformer.ts:25:21)
at Object.classToPlain (C:\Users\HP\nestjs-project\node_modules\src\index.ts:23:27)
I have installed all the necessary dependencies like ioredis
, graphql-redis-subscriptions
and even graphql-subscriptions
but the errors still exist. Redis also seems to be running properly.
I have tried reading the error logs but it did not occur in my source code and doing some research on StackOverFlow but none seems to have solved the problem.
Solution
Are you by any chance using a global ClassSerializerInterceptor
?? Because I was running into the same problem just today and I solved by removing the interceptor. It happened because the subscription needs to receive an instance of AsyncIterable
but the class serializer turns it into a plain object.
Apart from that I would recommend you change the GraphQl
config, remove the installSubscriptionHandlers
and change the config like this:
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
playground: true,
autoSchemaFile: path.join(process.cwd(), 'src/schema.gql'),
// remove this option:
// installSubscriptionHandlers: true,
// add the following:
subscriptions: {
"graphql-ws": true // or config object
}
}),
You can read more about it in the nestjs docs
I hope this solves your problem.
Answered By - Fran Messina Answer Checked By - Marie Seifert (PHPFixing Admin)
0 Comments:
Post a Comment
Note: Only a member of this blog may post a comment.