Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GraphQL/Relay Schema Cannot query field "store" on type "CreateLinkPayload"

I can successfully do graphql/relay queries and mutations with CURL and GraphiQL tool:

enter image description here

However, in my react/relay app I can query and get the data into the app, but every time I try to mutate something in my app, I get this error in the console:

    bundle.js:51511 Uncaught Error: GraphQL validation error ``Cannot query field "store" on type "CreateLinkPayload".`` in file 
`/Users/johndoe/react-relay-project/src/mutations/CreateLinkMutation.js`. Try updating your GraphQL schema if an argument/field/type was recently added.
(anonymous function) @ bundle.js:51511
getFatQuery @ bundle.js:51512
getFatQuery @ bundle.js:35664
getQuery @ bundle.js:35791
_handleCommit @ bundle.js:35539
commit @ bundle.js:35453
commit @ bundle.js:35894
(anonymous function) @ bundle.js:28526

and every time I do npm start I get this error:

-- GraphQL Validation Error -- CreateLinkMutation --

File:  /Users/johndoe/react-relay-project/src/mutations/CreateLinkMutation.js
Error: Cannot query field "store" on type "CreateLinkPayload".
Source:
> 
>         store { linkConnection }
>         ^^^

CreateLinkMutation.js

import Relay from 'react-relay'

class CreateLinkMutation extends Relay.Mutation {
  getMutation() {
    return Relay.QL`
      mutation { createLink }
    `
  }

  getVariables() {
    return {
      title: this.props.title,
      url: this.props.url
    }
  }

  getFatQuery() {
    return Relay.QL`
      fragment on CreateLinkPayload {
        linkEdge,
        store { linkConnection }
      }
    `
  }

  getConfigs() {
    return [{
      type: 'RANGE_ADD',
      parentName: 'store',
      parentID: this.props.store.id,
      connectionName: 'linkConnection',
      edgeName: 'linkEdge',
      rangeBehaviors: {
        '': 'append'
      }
    }]

  }
}

export default CreateLinkMutation

parts of Link.js

Link = Relay.createContainer(Link, {
  fragments: {
    link: () => Relay.QL`
      fragment on Link {
        url,
        title
      }
    `
  }
})

parts of App.js

 handleSubmit(e) {
    e.preventDefault()
    Relay.Store.update(
      new CreateLinkMutation({
        title: this.refs.newTitle.value,
        url: this.refs.newUrl.value,
        store: this.props.store
      })
    )
    this.refs.newTitle.value = ''
    this.refs.newUrl.value = ''
  }



App = Relay.createContainer(App, {
  initialVariables: {
    limit: 10
  },
  fragments: {
    store: () => Relay.QL`
      fragment on Store {
        id,
        linkConnection(first: $limit) {
          edges {
            node {
              id,
              ${Link.getFragment('link')}
            }
          }
        }
      }
    `

  }
})

parts of main.js

class LinkStoreRoute extends Relay.Route {
  static routeName = 'LinkStoreRoute'
  static queries = {
    store: () => Relay.QL`query { store }`
  }
}

My schema.js:

const store = {}

const Store = new GraphQLObjectType({
  name: 'Store',
  fields: () => ({
    id: globalIdField('Store'),
    linkConnection: {
      type: linkConnection.connectionType,
      args: connectionArgs,
      resolve: (_, args) => {
        return docClient.scan(
          Object.assign(
            {},
            {TableName: linksTable},
            paginationToParams(args)
          )
        ).promise().then(dataToConnection)
      }
    }
  })
})

const Link = new GraphQLObjectType({
  name: 'Link',
  fields: () => ({
    id: {
      type: new GraphQLNonNull(GraphQLID),
      resolve: (obj) => obj.id
    },
    title: { type: GraphQLString },
    url: { type: GraphQLString }
  })
})

const linkConnection = connectionDefinitions({
  name: 'Link',
  nodeType: Link
})

let createLinkMutation = mutationWithClientMutationId({

  name: 'CreateLink',

  inputFields: {
    title: { type: new GraphQLNonNull(GraphQLString) },
    url: { type: new GraphQLNonNull(GraphQLString) }
  },

  outputFields: {
    linkEdge: {
      type: linkConnection.edgeType,
      resolve: (obj) => ({node: obj, cursor: obj.id})
    }
  },

  store: {
    type: Store,
    resolve: () => store
  },

  mutateAndGetPayload: (inputFields) => {

    let link = {
      id: uuid.v4(),
      title: inputFields.title,
      url: inputFields.url
    }

    return new Promise((resolve, reject) => {
      docClient.put(
        Object.assign(
          {},
          {TableName: linksTable},
          {Item: link}
        ),
        (err, data) => {
          if (err) return reject(err)
          return resolve(link)
        }
      )
    })
  }
})

const schema = new GraphQLSchema({
  query: new GraphQLObjectType({
    name: 'Query',
    fields: () => ({
      store: {
        type: Store,
        resolve: () => store
      }
    })
  }),

  mutation: new GraphQLObjectType({
    name: 'Mutation',
    fields: () => ({
      createLink: createLinkMutation
    })
  })
})

module.exports = schema

Note that I excluded 40 lines of require statements at the top.

How is this even possible? And how can I fix it? Could it be a bug of relay/react?

like image 207
codepreneur Avatar asked Jul 31 '16 22:07

codepreneur


2 Answers

In your client-side implementation of CreateLinkMutation (CreateLinkMutation.js file), getFatQuery() function specifies that it expects two outputs after the mutation is complete - linkEdge and store. Therefore, in your server-side implementation of the mutation, you must include these two things as output. However, only linkEdge is included to the mutation's outputs in your current implementation (createLinkMutation in schema.js file). To solve the problem, include store to the outputs.

outputFields: {
  linkEdge: {
    type: linkConnection.edgeType,
    resolve: (obj) => ({node: obj, cursor: obj.id})
  },
  store: {
    type: Store,
    resolve: () => store
  },
},
like image 179
Ahmad Ferdous Avatar answered Sep 22 '22 02:09

Ahmad Ferdous


Turns out store

  store: {
    type: Store,
    resolve: () => store
  }

has to go inside outputFields like so:

  outputFields: {
    linkEdge: {
      type: linkConnection.edgeType,
      resolve: (obj) => ({node: obj, cursor: obj.id})
    }
    store: {
      type: Store,
      resolve: () => store
    }
  }
like image 40
codepreneur Avatar answered Sep 21 '22 02:09

codepreneur