2

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.
  ],
...
1
  • If I make the query nullable, remove the " ! ", then the query results are { "data": { "getMembers": null } } This seems to mean that data isn't being returned through the service which is currently working fine for my REST api's. Commented Mar 10, 2019 at 1:39

3 Answers 3

4

You probably imported @Query from '@nestjs/common' instead of '@nestjs/graphql'.

Make sure to have:

import { Query } from '@nestjs/graphql';
Sign up to request clarification or add additional context in comments.

9 Comments

Thanks Kim but I have that right. I found those other SO posts about this previously and was careful. Besides, I just copied Kamil's work for his Github demo :-)
Ok, pity, that would have been an easy fix. ;-) Have you added a console.log to your service and made sure that it is called and does actually return an non-empty array?
There's also a typo in your service but that's probably just copy/paste: userssRepository
I did put console.log in my service and resolver but nothing happened in the IDE terminal window.
I'll try but I have to learn about code sandbox first. Probably tomorrow because this is Woman's Day and my Russian wife wants to party :-) I'm American. So I haven't abandoned you if you don't hear from me for a while.
|
2

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

2 Comments

Thank you @MarsLevin! Yes, members.module was imported into app.module as lazy loaded. This is what made the REST code work well before I tried to setup GraphQL. I've since refactored and separated out the GraphQL components to make it easier to troubleshoot. Now I can get Nestjs to compile. I get the error No repository for "MembersGQL" was found. Looks like this entity is not registered in current "default" connection? I've added the refactored code and modules and part of the ormconfig.json to my original post. Any ideas?
I got it to present the users from my Postgres DB in Playground but I don't like that it has to use the REST entity. I want to remove all REST after I'm done converting to GraphQL.
0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.