BarakChamo
BarakChamo

Reputation: 3575

Edge.node field type must be Output Type but got: undefined

I'm trying to set up a node.js server with a Relay-compatible GraphQL schema.

When trying to validate or load the schema I get the following error:

EventEdge.node field type must be Output Type but got: undefined.

This is caused by having a connection type for for the Event type in one of the other type definitions.

I won't post the whole schema because it's quite verbose but when the connection field is commented out the schema is loaded correctly and no errors are thrown.

I've included an example of a simplified schema that causes the same issue:

  const graphql       = require('graphql')
  const relay         = require('graphql-relay')

  const GraphQLID         = graphql.GraphQLID,
        GraphQLInt        = graphql.GraphQLInt,
        GraphQLString     = graphql.GraphQLString,
        GraphQLList       = graphql.GraphQLList,
        GraphQLObjectType = graphql.GraphQLObjectType,
        GraphQLSchema     = graphql.GraphQLSchema,
        GraphQLNonNull    = graphql.GraphQLNonNull

  const connectionArgs               = relay.connectionArgs,
        connectionDefinitions        = relay.connectionDefinitions,
        connectionFromArray          = relay.connectionFromArray,
        cursorForObjectInConnection  = relay.cursorForObjectInConnection,
        fromGlobalId                 = relay.fromGlobalId,
        globalIdField                = relay.globalIdField,
        mutationWithClientMutationId = relay.mutationWithClientMutationId,
        nodeDefinitions              = relay.nodeDefinitions,
        toGlobalId                   = relay.toGlobalId

  // Models (ORM Mappings)
  const models = require('../models')

  // Model handlers
  const handlers = require('../models/handlers')


  /*
   *  Relay Node Definition:
   *  {nodeInterface, nodeField} = nodeDefinitions
   */

  var nodeDefinition = nodeDefinitions(
    (globalId) => {
      // {type, id} = fromGlobalId(globalId)
      const gid = fromGlobalId(globalId);

      switch (gid.type) {
      case 'User':
        return handlers.getUser(id)

      // case 'Event':
      //   return handlers.getEvent(id)
      //
      // case 'Club':
      //   return handlers.getClub(id)

      default:
        return null

      }
    },
    (obj) => {
      switch (true) {
        case (obj instanceof models.User):
          return UserType

        // case (obj instanceof models.Club):
        //   return ClubType
        //
        // case (obj instanceof models.Event):
        //   return EventType

        default:
          return null
      }
    }
  )

  /**************************
   **************************
   * Relay Connections
   *
   * { connectionType, edgeType } = connectionDefinitions({nodeType: LoremType})
   **************************
   **************************/

   // User Connection
   // const usersConnection = connectionDefinitions({name: 'User', nodeType: UserType})

   // Event Connection
   const eventsConnection = connectionDefinitions({name: 'Event', nodeType: EventType})

   // Club Connection
   // const clubsConnection = connectionDefinitions({name: 'Club', nodeType: ClubType})


   /**************************
    **************************
    * GraphQL Type Definitions
    **************************
    **************************/

    /*
    *   User Type
    *
    *   type User : Object {
    *     id: String!
    *     first_name: String
    *     last_name: String
    *     friends: [User]
    *   }
    */

   var UserType = new GraphQLObjectType({
     name: 'User',
     description: 'A user of the app.',
     fields: () => ({
       id: globalIdField('User'),
       events: {
         type: eventsConnection.connectionType,
         description: 'User\'s events.',
         args: connectionArgs,
         resolve: (user, args) => connectionFromArray(getEvents(), args)
       }
     }),
     interfaces: [nodeDefinition.nodeInterface]
   })


   /*
   **  Event Type
   *
   *   type Event : Object {
   *     id: String!
   *     title: String
   *     description: String
   *     datetime: Int
   *     location: [Int]
   *     managers: [User]
   *     club: Club
   *     members: [User]
   *   }
   */

  var EventType = new GraphQLObjectType({
    name: 'Event',
    description: 'An event in the app.',
    fields: () => ({
      id: globalIdField('Event'),
      name: {
        type: GraphQLString,
        description: 'Event\'s name.',
        resolve: event => event.get('name')
      }
    }),
    interfaces: [nodeDefinition.nodeInterface]
  })


  /****************************
   ****************************
   * Relay Mutation Definitions
   ****************************
   ****************************/


  /**************************
   **************************
   * Root Schema Definitions
   **************************
   **************************/

  /*
  **  Root Query
  *
  *   type Query {
  *     user(id: String!): User
  *     club(id: String!): Club
  *     event(id: String!): Event
  *   }
  */

  var QueryType = new GraphQLObjectType({
    name: 'Query',
    fields: () => ({
      node: nodeDefinition.nodeField,
      user: {
        type: UserType,
        resolve: () => handlers.getUser()
      }
    })
  })


  /*
  **  Root Schema
  *
  *   type Schema {
  *     query: Query
  *     mutation: Mutation
  *   }
  */

  var Schema = new GraphQLSchema({
    query: QueryType
  })


  module.exports = Schema

Upvotes: 5

Views: 5387

Answers (1)

steveluscher
steveluscher

Reputation: 4228

You've made a reference to EventType before assigning to it. First define the type, then make use of it in the connection:

/**
 *   Event Type
 *
 *   type Event : Object {
 *     id: String!
 *     title: String
 *     description: String
 *     datetime: Int
 *     location: [Int]
 *     managers: [User]
 *     club: Club
 *     members: [User]
 *   }
 */

var EventType = new GraphQLObjectType({
  name: 'Event',
  description: 'An event in the app.',
  fields: () => ({
    id: globalIdField('Event'),
    name: {
      type: GraphQLString,
      description: 'Event\'s name.',
      resolve: event => event.get('name')
    },
  }),
  interfaces: [nodeDefinition.nodeInterface],
});

// Event Connection
const eventsConnection = connectionDefinitions({
  name: 'Event', 
  nodeType: EventType,
});

Upvotes: 7

Related Questions