Tuesday 16 May 2017

GraphQL.js Interface type not recognized as Interface but as JS object

Disclaimer: This is my first question on StackOverflow. I tried to follow the rules and guidelines, but please let me know if I forgot something. I'm happy to provide more code/examples/explanation if that's necessary or helpful!

It seems like my 'Account' Interface that I want to use for a few different account types is not seen by GraphQL.js as a valid Interface type. I keep getting the following error message when trying to run Node with my GraphQL schema:

e:\Development\project-name\node_modules\graphql\jsutils\invariant.js:19
    throw new Error(message);
    ^

Error: RetailerAccount may only implement Interface types, it cannot implement: [object Object].
    at invariant (e:\Development\project-name\node_modules\graphql\jsutils\invariant.js:19:11)
    at e:\Development\project-name\node_modules\graphql\type\definition.js:310:29
    at Array.forEach (native)
    at defineInterfaces (e:\Development\project-name\node_modules\graphql\type\definition.js:309:14)
    at GraphQLObjectType.getInterfaces (e:\Development\project-name\node_modules\graphql\type\definition.js:288:52)
    at typeMapReducer (e:\Development\project-name\node_modules\graphql\type\schema.js:202:23)
    at Array.reduce (native)
    at typeMapReducer (e:\Development\project-name\node_modules\graphql\type\schema.js:198:34)
    at e:\Development\project-name\node_modules\graphql\type\schema.js:216:20
    at Array.forEach (native)
    at typeMapReducer (e:\Development\project-name\node_modules\graphql\type\schema.js:207:27)
    at e:\Development\project-name\node_modules\graphql\type\schema.js:216:20
    at Array.forEach (native)
    at typeMapReducer (e:\Development\project-name\node_modules\graphql\type\schema.js:207:27)
    at Array.reduce (native)
    at new GraphQLSchema (e:\Development\project-name\node_modules\graphql\type\schema.js:95:34)
    at Object.<anonymous> (e:\Development\project-name\api\config\graphql.config.js:8:14)
    at Module._compile (module.js:571:32)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:488:32)
    at tryModuleLoad (module.js:447:12)
    at Function.Module._load (module.js:439:3)
[nodemon] app crashed - waiting for file changes before starting...

This is the code for my Account Interface:

var path = require('path');
var graphql = require('graphql');

// Custom Enum types
var enums = require(path.join(__dirname, 'enums'));

// Custom Scalar types
var scalars = require(path.join(__dirname, 'scalars'));

// Required ObjectTypes for fields
var Phone = require(path.join(__dirname, 'phone.type'));
var Address = require(path.join(__dirname, 'address.type'));
var Order = require(path.join(__dirname, 'order.type'));
var Upload = require(path.join(__dirname, 'upload.type'));

// ObjectTypes that implement this Interface, used for the resolveType() function
var UserAccount = require(path.join(__dirname, 'userAccount.type'));
var RetailerAccount = require(path.join(__dirname, 'retailerAccount.type'));
var WholesalerAccount = require(path.join(__dirname, 'wholesalerAccount.type'));
var ManufacturerAccount = require(path.join(__dirname, 'manufacturerAccount.type'));
var AdminAccount = require(path.join(__dirname, 'adminAccount.type'));

module.exports = new graphql.GraphQLInterfaceType({
    name: 'Account',
    fields: function() {
        return {
            _id: {type: new graphql.GraphQLNonNull(graphql.GraphQLID)},
            email: {type: new graphql.GraphQLNonNull(graphql.GraphQLString)},
            username: {type: new graphql.GraphQLNonNull(graphql.GraphQLString)},
            password: {type: new graphql.GraphQLNonNull(graphql.GraphQLString)},
            passwordSalt: {type: new graphql.GraphQLNonNull(graphql.GraphQLString)},
            verificationCode: {type: new graphql.GraphQLNonNull(graphql.GraphQLString)},
            isVerified: {type: new graphql.GraphQLNonNull(graphql.GraphQLBoolean)},
            mustResetPassword: {type: new graphql.GraphQLNonNull(graphql.GraphQLBoolean)},
            dateLastLoggedIn: {type: scalars.Date},
            role: {type: new graphql.GraphQLNonNull(enums.AccountRole)},
            initials: {type: graphql.GraphQLString},
            firstName: {type: new graphql.GraphQLNonNull(graphql.GraphQLString)},
            lastNamePrefix: {type: graphql.GraphQLString},
            lastName: {type: new graphql.GraphQLNonNull(graphql.GraphQLString)},
            gender: {type: graphql.GraphQLBoolean},
            dateOfBirth: {type: scalars.Date},
            phone: {type: new graphql.GraphQLList(new graphql.GraphQLNonNull(Phone))},
            address: {type: new graphql.GraphQLList(new graphql.GraphQLNonNull(Address))},
            orders: {type: new graphql.GraphQLList(new graphql.GraphQLNonNull(Order))},
            uploads: {type: new graphql.GraphQLList(new graphql.GraphQLNonNull(Upload))},
            preferredLanguage: {type: new graphql.GraphQLNonNull(enums.Language)},
        }
    },
    resolveType(data) {
        switch(data.AccountRole) {
            case 'USER' || 0:
                return UserAccount;
            case 'RETAILER' || 1:
                return RetailerAccount;
            case 'WHOLESALER' || 2:
                return WholesalerAccount;
            case 'MANUFACTURER' || 3:
                return ManufacturerAccount;
            case 'ADMIN' || 4:
                return AdminAccount;
            default:
                return UserAccount;
        }
    }
});

And this is the code for one of the implementing ObjectTypes (the one that gives the error message currently):

var path = require('path');
var graphql = require('graphql');

// Required Interfaces
var Account = require(path.join(__dirname, 'account.interface'));
var Metadata = require(path.join(__dirname, 'metadata.interface'));
var Name = require(path.join(__dirname, 'name.interface'));

// Required ObjectTypes
var Retailer = require(path.join(__dirname, 'retailer.type'));
var Shop = require(path.join(__dirname, 'shop.type'));

module.exports = new graphql.GraphQLObjectType({
    name: 'RetailerAccount',
    interfaces: [Account, Metadata, Name],
    fields: function() {
        return {
            retailer: {type: new graphql.GraphQLNonNull(Retailer)},
            shops: {type: new graphql.GraphQLList(new graphql.GraphQLNonNull(Shop))}
        }
    }
});

The strange thing is that the other interfaces that these Account types implement seem to be working without any problems. I don't get this error message anymore when I remove the Account interface. I've been looking over the syntax, trying to find differences with Name or Metadata. I've also been making changes (and reverting them) to the resolveType() function, the AccountRole enum, and the Interface and the ObjectType themselves, but that doesn't help either.

I'm using the following versions:

  • npm 4.2.0
  • node 7.8.0
  • graphql 0.9.3
  • express-graphql 0.6.4
  • express 4.15.2

Some pages that I used while trying to figure out what was wrong with my code (I wasn't able to fix my issue with any of them):

I don't have enough reputation yet, so I can't post more links apparently.

Can someone here maybe help me out with this? Thanks!



via Thomas Dingemanse

No comments:

Post a Comment