graphqlgraphql-jsexpress-graphqltypegraphqltypegoose

Cannot return null for non-nullable field - Typegoose and TypeGraphQL


I have this Album model set up using Typegoose and TypeGraphQL, which contains multiple songs from the Song model using the AlbumSong ObjectType:

import {
  prop as Property,
  getModelForClass,
  modelOptions,
  Ref,
} from "@typegoose/typegoose";
import { Field, ObjectType, ID } from "type-graphql";
import { AlbumCategory, } from "./albumCategory.model";
import { Song } from "./song.model";

@ObjectType()
export class AlbumSong {
  @Field(() => ID)
  @Property({ required: true })
  id!: string;

  @Field(() => Song)
  @Property({ type: () => Song, ref: () => Song, required: true })
  song!: Song;
}

@ObjectType({ description: "The Album Model" })
@modelOptions({ schemaOptions: { collection: "albums", timestamps: true } })
export class Album {
  @Field(() => ID)
  id: string;

  @Field()
  @Property({ type: () => String })
  title: string;

  @Field(() => [AlbumSong])
  @Property({ type: AlbumSong })
  albumSongs!: Partial<AlbumSong>[];


  @Field()
  @Property({ required: true, default: Date.now })
  createdAt: Date;

  @Field()
  @Property({ required: true, default: Date.now })
  updatedAt: Date;
}
export const AlbumModel = getModelForClass(Album);

When trying to query the album using:

@Query((_returns) => Album, { nullable: false, name: "album" })
async getAlbumById(@Arg("id") id: string) {
  return await AlbumModel.findById({ _id: id });
}

With the following GraphQL:

query Album($albumId: String!) {
  album(id: $albumId) {
    id
    albumSongs {
      id
      song {
        id
      }
    }
  }
}

I get: "Cannot return null for non-nullable field AlbumSong.song."

To me it seems like the reference is not working, when i only query the albumSong's id it returns just fine...


Solution

  • Setup a FieldResolver to resolve the song within an AlbumSong

    @Resolver(() => AlbumSong)
    export class AlbumSongFieldResolver {
      @FieldResolver(() => Song)
      async song(@Root() parent: AlbumSong): Promise<Song> {
        return Song.findOne(parent.song);
      }
    }