I have a problem with Nestjs, with starting a microservice that listens to a messagebroker, while simultaneously starting a websocket server with which we can communicate with front-end clients.
So I am aware of hybrid nest applications, where the websocket gateway can be injected into the microservice. However I get errors about Nest not being able to resolve the Gateway import.
I configured the microservice in a ResultsModule, the websocket in UsersModule.
The error I get is:
ERROR [ExceptionHandler] Nest can't resolve dependencies of the ResultsController (ResultsService, ?). Please make sure that the argument UsersGateway at index [1] is available in the ResultsModule context.
These are the relevant pieces of code:
main.js
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.connectMicroservice<MicroserviceOptions>({
transport: Transport.RMQ,
options: {
urls: [
`amqp://${config.rabbitmq.username}:${config.rabbitmq.password}#${config.rabbitmq.host}:${config.rabbitmq.port}`,
],
queue: config.rabbitmq.channelListen,
noAck: false,
queueOptions: {
durable: false,
},
},
});
await app.startAllMicroservices();
await app.listen(82);
}
bootstrap();
app.module.ts
#Module({
imports: [UsersModule, ResultsModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
results.module.ts
#Module({
imports: [UsersModule],
controllers: [ResultsController],
providers: [ResultsService],
})
export class ResultsModule {}
users.module.ts
#Module({
providers: [UsersGateway, UsersService],
})
export class UsersModule {}
users.gateway.ts
import {
WebSocketGateway,
SubscribeMessage,
MessageBody,
OnGatewayInit,
OnGatewayConnection,
OnGatewayDisconnect,
WebSocketServer,
ConnectedSocket,
} from '#nestjs/websockets';
import { Socket, Server } from 'socket.io';
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
#WebSocketGateway(82)
export class UsersGateway
implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect
{
constructor(private readonly usersService: UsersService) {}
#WebSocketServer() server: Server;
afterInit(server: Server) {
console.log('init');
}
handleDisconnect(client: Socket) {
console.log(`Client disconnected: ${client.id}`);
}
handleConnection(client: Socket, ...args: any[]) {
console.log(client.id);
}
#SubscribeMessage('resource')
create(
#MessageBody() createUserDto: CreateUserDto,
#ConnectedSocket() client: Socket,
) {
console.log(client.id);
console.log(createUserDto.resourceId)
}
}
I tried to move around the imports, not wrapping the gateway in a module.
Tried moving the results module out of the app.module. Which removes the error, however then I do not understand where to let nestjs know to use the resultsmodule for the microservice.
------------------------ANSWER-------------------------------------
Alright, we fixed it with the help of #yomateo , we were missing the export of the websocket gateway in the module. Thanks for the help!
You're close (you have it backwards).
Have your UsersGateway or UsersService call the ResultsService.
Related
Below is my code
I tried to set a web socket gateway as below.
events.gateways.ts
import {
MessageBody,
SubscribeMessage,
WebSocketGateway,
WebSocketServer,
} from "#nestjs/websockets";
import { Server } from "socket.io";
#WebSocketGateway({
cors: {
origin: "http://localhost:3000",
},
})
export class EventsGateway {
#WebSocketServer()
server: Server;
#SubscribeMessage("events")
handleEvent(#MessageBody() data: string): string {
return data;
}
}
I set above gateway as a provider to a module.
events.module.ts
import { Module } from "#nestjs/common";
import { EventsGateway } from "./events.gateway";
#Module({
providers: [EventsGateway],
})
export class EventsModule {}
Fianllt, i imported above module to the app.module.ts and now I am getting the error
app.module.ts
import { Module } from "#nestjs/common";
import { AppController } from "./app.controller";
import { AppService } from "./app.service";
import { APP_FILTER } from "#nestjs/core";
import { AllExceptionFilter } from "./all-exception.filter";
import { ConfigModule } from "#nestjs/config";
import { TypeOrmModule } from "#nestjs/typeorm";
import { Student } from "./student/entities/student.entity";
import { EventsModule } from "./events/events.module";
#Module({
imports: [
ConfigModule.forRoot(),
TypeOrmModule.forRoot({
type: "postgres",
host: process.env.DB_HOST,
port: parseInt(process.env.DB_PORT as string) | 5432,
username: process.env.DB_USERNAME,
password: process.env.DB_PASSWORD,
database: process.env.DB_DATABASE,
entities: [Student],
synchronize: true,
}),
EventsModule,
],
controllers: [AppController],
providers: [
{
provide: APP_FILTER,
useClass: AllExceptionFilter,
},
AppService,
],
})
export class AppModule {}
This is the error I am keep getting.
TypeError: this.graphInspector.insertEntrypointDefinition is not a function
at /home/Desktop/New Folder/nest_try_1/node_modules/#nestjs/websockets/web-sockets-controller.js:108:33
at Array.forEach (<anonymous>)
at WebSocketsController.inspectEntrypointDefinitions (/home/Desktop/New Folder/nest_try_1/node_modules/#nestjs/websockets/web-sockets-controller.js:106:25)
at WebSocketsController.subscribeToServerEvents (/home/Desktop/New Folder/nest_try_1/node_modules/#nestjs/websockets/web-sockets-controller.js:39:14)
at WebSocketsController.connectGatewayToServer (/home/Desktop/New Folder/nest_try_1/node_modules/#nestjs/websockets/web-sockets-controller.js:30:14)
at SocketModule.connectGatewayToServer (/home/Desktop/New Folder/nest_try_1/node_modules/#nestjs/websockets/socket-module.js:47:35)
at /home/Desktop/New Folder/nest_try_1/node_modules/#nestjs/websockets/socket-module.js:36:38
at IteratorWithOperators.forEach (/home/Desktop/New Folder/nest_try_1/node_modules/iterare/lib/iterate.js:157:13)
at SocketModule.connectAllGateways (/home/Desktop/New Folder/nest_try_1/node_modules/#nestjs/websockets/socket-module.js:36:14)
at /home/Desktop/New Folder/nest_try_1/node_modules/#nestjs/websockets/socket-module.js:31:61
Node.js v19.4.0
I am follwing the documentation and I am keep getting above error.
you should align your dependencies, ie., if you're using #nestjs/websockets v9.3.1, #nestjs/core must be in v9.3.1 as well
Run npx nest info and check that out.
That error is because #nestjs/websockets is invoking a method added in v9.3 which depends on a method added in v9.3 of #nestjs/core as well.
btw there are closed issues on GitHub about that error: https://github.com/nestjs/nest/issues?q=is%3Aissue+sort%3Aupdated-desc+is%3Aclosed+insertEntrypointDefinition
I am trying to build a nestjs graphql with federation Schema with schema first approach monorepo of two microservices AUTH and LEDGER and a GATEWAY the AUTH microservice appModule.ts looks like this:
import { AuthModule } from './../auth/auth.module';
import { Module } from '#nestjs/common';
import { GraphQLModule } from '#nestjs/graphql';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { join } from 'path';
import { ApolloFederationDriver, ApolloFederationDriverConfig } from '#nestjs/apollo';
#Module({
imports: [
GraphQLModule.forRoot<ApolloFederationDriverConfig>({
driver: ApolloFederationDriver,
autoSchemaFile: join(process.cwd(), 'src/schema.gql'),
context: ({ req }) => ({ req }),
useGlobalPrefix: true,
}),
AuthModule
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
However I keep getting Error: Cannot find module 'apollo-server-core'. Now I am not using apollo-server-core directly I am using apollo/server v4 and V10 of nest/graphql and nest/apollo. I also understand that nestjs v9 may not be updated to apollo/server v4. can anyone shed some light on this?...what is causing this error? is there a workaround?
At this time, nestjs is not compatible with v4. You can check this: https://github.com/nestjs/graphql/issues/2445
Nestjs application does not display the error message during development only during production. I found no module where the apollo -server can be configured to cache: "bounded". The Nestjs documentation itself makes no mention of it anywhere.
The complete error message says:
Persisted queries are enabled and are using an unbounded cache. Your server is vulnerable to denial of service attacks via memory exhaustion. Set cache: "bounded" or persistedQueries: false in your ApolloServer constructor, or see https://go.apollo.dev/s/cache-backends for other alternatives.
Here are some dependencies I suspect could be related to it.
"#nestjs/apollo": "10.0.19",
"#nestjs/common": "9.0.5",
"#nestjs/core": "9.0.5",
"#nestjs/graphql": "10.0.20",
A similar issue was opened at github and sadly it was closed without any solution.
This is related to the Apollo module's configuration, by default the cache is "unbounded" and not safe for production (see : https://www.apollographql.com/docs/apollo-server/performance/cache-backends/#ensuring-a-bounded-cache)
You can easily follow their recommendation by adding the optional "cache" configuration inside your GraphQL module.
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
cache: 'bounded', // <--- This option
...
}
Or provide an external caching with KeyvAdapter see: https://github.com/apollographql/apollo-utils/tree/main/packages/keyvAdapter#keyvadapter-class
In the app.module.ts inside the import array,
GraphQLModule.forRootAsync<ApolloDriverConfig>({
driver: ApolloDriver,
useClass: GqlConfigService,
}),
Then in the GqlConfigService I add cache: 'bounded' in the ApolloDriverConfig options.
import { ConfigService } from '#nestjs/config';
import { ApolloDriverConfig } from '#nestjs/apollo';
import { Injectable } from '#nestjs/common';
import { GqlOptionsFactory } from '#nestjs/graphql';
import { GraphqlConfig } from './config.interface';
#Injectable()
export class GqlConfigService implements GqlOptionsFactory {
constructor(private configService: ConfigService) {}
createGqlOptions(): ApolloDriverConfig {
const graphqlConfig = this.configService.get<GraphqlConfig>('graphql');
return {
// schema options
cache: 'bounded', // ! <== Added here
autoSchemaFile: graphqlConfig.schemaDestination || './src/schema.graphql',
sortSchema: graphqlConfig.sortSchema,
buildSchemaOptions: {
numberScalarMode: 'integer',
},
// subscription
installSubscriptionHandlers: true,
debug: graphqlConfig.debug,
playground: graphqlConfig.playgroundEnabled,
context: ({ req }) => ({ req }),
};
}
}
I'm trying to serve static files, an image in my case, in my nestjs microservice.
Has anyone an idea of how to do that?
The only information I can find is how to serve static files in normal nestjs applications, but not how to with a microservice application.
from the docs
import { Module } from '#nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ServeStaticModule } from '#nestjs/serve-static';
import { join } from 'path';
#Module({
imports: [
ServeStaticModule.forRoot({
rootPath: join(__dirname, '..', 'client'),
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Oke I fixed it to serve the image in the 'main-service' which is an api that connects to the microservices.
Used the example above and the docs to do it.
I'm trying to integrate nestjs with prisma. I followed the tutorial in nestjs document.
Everthing works fine until I want to make some changes so nestjs doesn't expose all the query/mutations schema.
what I did is
1. update app module not let typePath include the generated schema
import { Module } from '#nestjs/common';
import { AppController } from 'app/app.controller';
import { AppService } from 'app/app.service';
import { GraphQLModule } from '#nestjs/graphql';
import { UserModule } from './user/user.module';
#Module({
imports: [
GraphQLModule.forRoot({
typePaths: ['./src/**/*.schema.graphql'],
debug: true,
playground: true,
}),
UserModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
2. Then I created a user.schema.graphql file in user folder:
#import User from "../prisma/generated/prisma.graphql"
type Query {
user(id: ID!): User
}
However, I got some error saying I can't import User:
(node:36277) UnhandledPromiseRejectionWarning: Error: Type "User" not found in document.
at ASTDefinitionBuilder._resolveType (/Users/anx/Projects/axesk/gallery-api/node_modules/graphql/utilities/buildASTSchema.js:100:11)
at ASTDefinitionBuilder.buildType (/Users/anx/Projects/axesk/gallery-api/node_modules/graphql/utilities/buildASTSchema.js:210:79)
at ASTDefinitionBuilder._buildWrappedType (/Users/anx/Projects/axesk/gallery-api/node_modules/graphql/utilities/buildASTSchema.js:229:17)
at ASTDefinitionBuilder.buildField (/Users/anx/Projects/axesk/gallery-api/node_modules/graphql/utilities/buildASTSchema.js:249:18)
at /Users/anx/Projects/axesk/gallery-api/node_modules/graphql/utilities/buildASTSchema.js:332:21
at /Users/anx/Projects/axesk/gallery-api/node_modules/graphql/jsutils/keyValMap.js:36:31
at Array.reduce (<anonymous>)
at keyValMap (/Users/anx/Projects/axesk/gallery-api/node_modules/graphql/jsutils/keyValMap.js:35:15)
at ASTDefinitionBuilder._makeFieldDefMap (/Users/anx/Projects/axesk/gallery-api/node_modules/graphql/utilities/buildASTSchema.js:329:48)
at fields (/Users/anx/Projects/axesk/gallery-api/node_modules/graphql/utilities/buildASTSchema.js:312:22)
(node:36277) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
(node:36277) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
I'm new to nestjs and graphql, please help!
I make it work in sort of hack way.. i will just paste my solution here for anyone who got same problem.
For example i have a user.schema.graphql that import some type from prisma.graphql:
#import User from "../prisma/generated/prisma.graphql"
type Query {
user(id: ID!): User
}
Then i create a main.schema.graphql file that will import every schemas from the project manually.
#import * from "./user/user.schema.graphql"
Finally just import this maim schema to app.module.ts:
import { Module } from '#nestjs/common';
import { AppController } from 'app/app.controller';
import { AppService } from 'app/app.service';
import { GraphQLModule } from '#nestjs/graphql';
import { UserModule } from './user/user.module';
import { importSchema } from 'graphql-import';
#Module({
imports: [
GraphQLModule.forRoot({
resolverValidationOptions: {
requireResolversForResolveType: false,
},
typeDefs: importSchema('./src/main.schema.graphql'),
debug: true,
playground: true,
}),
UserModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Doing this not really ideal. if graphql-import library can import from folders, it makes life easier.
or the #nest/graphql library can use graphql-import instead of merge-graphql-schemas under the hood to build typeDefs will be also great.