lorm
lorm

Reputation: 3361

React/GraphQL: Can only create NonNull of a Nullable GraphQLType but got 'type'

I am working on my first GraphQL schema. I've never done this before, and I am confused by the errors that I get. For instance:

  /Users/lorm/projects/aggregated_centralized_api/node_modules/graphql/jsutils/invariant.js:20
      throw new Error(message);
      ^

  Error: Can only create NonNull of a Nullable GraphQLType but got: function GraphQLList(type) {
      _classCallCheck(this, GraphQLList);

      (0, _jsutilsInvariant2['default'])(isType(type), 'Can only create List of a GraphQLType but got: ' + type + '.');
      this.ofType = type;
    }.
      at invariant (/Users/lorm/projects/aggregated_centralized_api/node_modules/graphql/jsutils/invariant.js:20:11)
      at new GraphQLNonNull (/Users/lorm/projects/aggregated_centralized_api/node_modules/graphql/type/definition.js:761:39)
      at Object.<anonymous> (/Users/lorm/projects/aggregated_centralized_api/server/schema.js:121:19)
      at Module._compile (module.js:413:34)
      at normalLoader (/Users/lorm/projects/aggregated_centralized_api/node_modules/babel-core/lib/api/register/node.js:199:5)
      at Object.require.extensions.(anonymous function) [as .js] (/Users/lorm/projects/aggregated_centralized_api/node_modules/babel-core/lib/api/register/node.js:216:7)
      at Module.load (module.js:357:32)
      at Function.Module._load (module.js:314:12)
      at Module.require (module.js:367:17)
      at require (internal/module.js:16:19)

My schemaTypes.js file looks like this:

  export const BookType = new GraphQLObjectType({
      name: 'Book',
      description: 'A Book',
      fields: () => ({
    book_id: {
        type: GraphQLString,
        description: 'UUID for book',
    },
    title: {
        type: GraphQLString,
        description: 'The name of the book',
    },
    author: {
        type: GraphQLList,
        description: 'List of authors, each author an object',
    },
    isbn: {
        type: GraphQLString,
        description: 'The primary way of identifying the book both domestically and internationally',
    },
    agency_price: {
        type: GraphQLFloat,
        description: 'The price set by the agency',
    },
    pub_date: {
        type: GraphQLString,
        description: 'The publication date of the book',
    },
    amazon_rank: {
        type: GraphQLInt,
        description: "The book's current selling rank on Amazon, updated daily",
    },
    reviews: {
        type: GraphQLFloat,
        description: "The book's current average review rating on Amazon, can 1 to 5, accurate to 1 decimal, updated daily",
    },
    book_img: {
        type: GraphQLString,
        description: 'Absolute URL for the image used for the book cover',
    },
    asin: {
        type: GraphQLString,
        description: "Amazon Standard Identification Numbers (ASINs) are unique blocks of 10 letters and/or numbers that identify items",
    },
    publisher: {
        type: GraphQLString,
        description: "The publisher name. There is only one publisher per book.",
    },
    bisacs: {
        type: GraphQLList,
        description: 'A list of Book Industry Standards and Communications subject headings as strings',
    },
    series_name: {
        type: GraphQLString,
        description: "If the book belongs to a series, the name of the series",
    },
    volume: {
        type: GraphQLString,
        description: "If the book is part of a series, this is its location in the sequence",
    },
    formats: {
        type: GraphQLList,
        description: 'Open Road has 20 standard formats',
    },
    keywords: {
        type: GraphQLList,
        description: 'Open Road puts mulitiple keywords (separated by a semi-colon) into the keyword1 field in Firebrand',
    },
    description: {
        type: GraphQLString,
        description: "Open Road's summary of the book",
    },
    campaigns: {
        type: GraphQLList,
        description: "A list full of marketing Campaigns we've done for the author",
    },
    retailers: {
        type: GraphQLList,
        description: 'A list full of Retailers, holding data specific to this book',
    },
    nominations: {
        type: GraphQLList,
        description: 'A list full of nominations to which this book belongs',
    },
    created: {
        type: GraphQLInt,
        description: 'The creation timestamp of this book'
    }
      })
  });

And by schema.js looks, in part, like this:

  let schema = new GraphQLSchema({
    query: new GraphQLObjectType({
      name: 'RootQueryType',
      fields: {
        book: {
          type: new GraphQLList(BookType),
          resolve: () => ""
        },
        book_retailer_summary: {
          type: BookRetailerSummaryType,
          args: {
            name: {
              description: 'Summary of books sales information, via various retailers',
              type: new GraphQLNonNull(GraphQLString)
            }
          },
          resolve: (root, {name}) => {
            return mongo()
              .then(db => {
                let deferred = Q.defer();

                let collection = db.collection('users');
                collection.find({ name })
                  .toArray((err, docs) => {
                    if (err) {
                      deferred.reject(err);
                      return;
                    }

                    db.close();
                    deferred.resolve(docs.length ? docs[0] : null);
                  });

                return deferred.promise;
              });

          }
        }
      }
    }),

So I am curious what mistake I am making?

[[ UPDATE ]]

Responding to helfer's remarks I have to wonder about this use of GraphQLList:

  nomination: {
    type: NominationType,
    args: {
      name: {
        description: 'The name of the list of books',
        type: new GraphQLNonNull(GraphQLString)
      },
      books: {
        description: 'The name of the books belonging to this nomination',
        type: new GraphQLNonNull(GraphQLList)
      }
    },

Perhaps this line is not allowed?

        type: new GraphQLNonNull(GraphQLList)

Is there some way I can get better error messages, so I can narrow in on what the real problem is?

Upvotes: 1

Views: 1414

Answers (1)

helfer
helfer

Reputation: 7182

GraphQLList and GraphQLNonNull are wrapping types, that means they always have to be created as follows:

const someListType = new GraphQLList(anotherType);
const someNonNullType = new GraphQLNonNull(anotherType);

Your book type has many fields that have the type GraphQLListType without actually creating an instance (i.e. without calling new and passing the type to wrap). The error message indicates that you're trying to wrap a GraphQLListType in NonNull somewhere, but it doesn't work because you didn't create the list type properly.

By the way, the schemas can get quite long and hard to read in Javascript, which is why I've created a package that lets you write them in schema language so it's much easier to read:

type Book {
  book_id: String
  title: String
  author: [Author]
  # etc.
}

You can find the documentation here: http://docs.apollostack.com/apollo-server/generate-schema.html

Upvotes: 1

Related Questions