Reputation: 3528
Playground in my browser shows the Nestjs created schema nicely but queries are returning null
. Is there something wrong with my code?
"errors": [
{
"message": "Cannot return null for non-nullable field Query.getUsers.",
"locations": [
{
"line": 2,
"column": 3
}
This means no data found.
schema.graphql:
type UsersGQL {
User_id: ID!
first_name: String!
last_name: String!
main_skill_title: String!
user_name: String!
....
}
type Query {
getUser(user_id: ID!): UsersGQL!
getUsers: [UsersGQL!]!
}
Compiles in Nestjs with GraphQL to graphql.schema.ts
export class UsersGQL {
user_id: string;
first_name: string;
last_name: string;
main_skill_title: string;
user_name: string;
...
}
export abstract class IQuery {
abstract getUser(user_id: string): UsersGQL | Promise<UsersGQL>;
abstract getUsers(): UsersGQL[] | Promise<UsersGQL[]>;
abstract temp__(): boolean | Promise<boolean>;
}
users.resolvers.ts
import { Query, Resolver } from '@nestjs/graphql';
import { UsersService } from './users.service';
import { UsersGQL } from '../graphql.schema';
// import { UsersDTO } from './users.dto';
@Resolver('UsersGQL')
export class UsersResolvers {
constructor(
private readonly userService: UsersService
) {}
@Query()
async getUsers() {
return await this.userService.findAll();
}
}
The service works fine for my Nestjs REST API's. The db is Postgres.
users.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, getManager, getRepository } from 'typeorm';
import { Members } from './members.entity';
@Injectable()
export class UsersService {
private entityManager = getManager();
constructor(
@InjectRepository(Users)
private readonly usersRepository: Repository<Users>
) {}
async findAll(): Promise<Users[]> {
return await this.usersRepository.find();
}
}
Playground query:
{
getUsers {
first_name
last_name
}
}
The error returned in Playground:
{
"errors": [
{
"message": "Cannot return null for non-nullable field Query.getUsers.",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"getUsers"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"stacktrace": [
...
],
"data": null
}
Edit - added users.module.ts, app.module.ts and ormconfig.json. This whole module is lazy loaded. REST and GraphQL are side by side in the module. I also separated REST and GQL components.
users.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
// REST
import { UsersService } from './users.service';
import { UsersController } from './users.controller';
import { Users } from './users.entity';
// GraphQL
import { UsersResolvers } from './users.resolvers';
@Module({
imports: [
TypeOrmModule.forFeature([
Users
]),
],
providers: [
UsersService,
UsersResolvers
],
controllers: [UsersController],
})
export class UsersModule {}
app.module.ts
import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { GraphQLModule } from '@nestjs/graphql';
import { join } from 'path';
import { LoggerMiddleware } from './logger.middleware';
import { UsersModule } from './users/users.module';
import { UsersController } from './users/users.controller';
@Module({
imports: [
TypeOrmModule.forRoot(),
GraphQLModule.forRoot({
typePaths: ['./**/*.graphql'],
definitions: {
path: join(process.cwd(), 'src/graphql.schema.ts'),
outputAs: 'class',
},
debug: true,
}),
UsersModule
],
controllers: [
],
exports: [
],
providers: [
]
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(LoggerMiddleware)
.with('AppModule')
.forRoutes(
UsersController
)};
}
ormconfig.json
...
"entities": [
"src/**/**.entity{.ts,.js}",
// "src/graphql.schema.ts" This doesn't work. Must use REST entity.
],
...
Upvotes: 2
Views: 4951
Reputation: 3528
The "solution" with this TypeORM architecture is to use the TypeORM entity.
users.resolvers.ts
import { Query, Resolver } from '@nestjs/graphql';
import { UsersService } from './users.service';
import { Users } from './users.entity'; // Here
@Resolver('Users')
export class UsersResolvers {
constructor(
private readonly userService: UsersService
) {}
@Query()
async getUsers() {
return await this.userService.findAll();
}
}
Upvotes: 0
Reputation: 181
TL;DR
The fact that your schema is correctly exposed (and available via the playground) doesn't necessarily mean that all the corresponding modules and resolvers are integrated into your running Nest application.
I recently faced the same error and the reason was quite straightforward: I had forgotten to import the module including the resolver into the root module — usually AppModule
.
So: are you sure you have all your UserModule
module dependencies (and above all the UserResolver
) imported and the UsersModule
itself imported into your AppModule
?
The trick here is that the GraphQL schema exposed by your server is directly generated from your source files. According to your Nest GraphQL configuration, it will compile all the .graphql
, .gql
files together (schema first approach) ; or the type-graphql module, with Nest v6, will read all your source files looking for its decorators and generate the schema.gql
(code first approach). As a consequence, you can expose a correct schema even having no actual module resolving your request.
IMO, it's a buggy behaviour from the framework as it silently fails to resolve your schema without providing any explanation. The simple error message you get (Cannot return null for non-nullable field Query.getUsers.
) is quite misleading as it hides the real failure, which is a broken dependency.
For more information, here is the related GitHub issue: https://github.com/nestjs/graphql/issues/198
Upvotes: 2
Reputation: 60347
You probably imported @Query
from '@nestjs/common'
instead of '@nestjs/graphql'
.
Make sure to have:
import { Query } from '@nestjs/graphql';
Upvotes: 4