Running Nestjs version 9 with Graphql and apollo server v4 gives Error: Cannot find module 'apollo-server-core' - graphql

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

Related

Nestjs Hybrid application websocket + microservice

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.

Nestjs displays error during production that: "Persisted queries are enabled and are using an unbounded cache."

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 }),
};
}
}

When I run nest.js, I get a Missing "driver" option error

I am using nest.js, prisma, and graphql.
When I run the npm run start:dev command, I get an error.
If anyone knows how to solve this, please let me know.
ERROR [GraphQLModule] Missing
"driver" option. In the latest version of "#nestjs/graphql" package
(v10) a new required configuration property called "driver" has been
introduced. Check out the official documentation for more details on
how to migrate (https://docs.nestjs.com/graphql/migration-guide).
Example:
GraphQLModule.forRoot({
driver: ApolloDriver,
})
app.module.ts
import { Module } from '#nestjs/common';
import { GraphQLModule } from '#nestjs/graphql';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ApolloServerPluginLandingPageLocalDefault } from 'apollo-server-core';
import { DonationsModule } from './donations/donations.module';
#Module({
imports: [
GraphQLModule.forRoot({
playground: false,
plugins: [ApolloServerPluginLandingPageLocalDefault()],
typePaths: ['./**/*.graphql'],
}),
DonationsModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
generate-typings.ts
import { GraphQLDefinitionsFactory } from '#nestjs/graphql';
import { join } from 'path';
const definitionsFactory = new GraphQLDefinitionsFactory();
definitionsFactory.generate({
typePaths: ['./src/**/*.graphql'],
path: join(process.cwd(), 'src/graphql.ts'),
outputAs: 'class',
watch: true,
});
fix
#Module({
imports: [
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
autoSchemaFile: true,
plugins: [ApolloServerPluginLandingPageLocalDefault()],
typePaths: ['./**/*.graphql'],
}),
DonationsModule,
],
controllers: [AppController],
providers: [AppService],
})
Checkout the nestjs/graphql documentation page and the other link that you have mentioned. You have to configure your GraphQLModule like this which I don't see in your code.
#Module({
imports: [
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
}),
],
})
Also don't forget to import
import { ApolloDriverConfig, ApolloDriver } from '#nestjs/apollo';

serve static files in microservice

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.

How to only expose part of prima generated schema in nestjs

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.

Resources