Search code examples
jsonnode.jsgraphqlgraphql-jshttpie

Using variables in GraphQL object query


I'm working through the GraphQL JS tutorial and trying to understand how variables work with the queries.

In the Object Types section I can get this working fine:

My server.js file:

const express = require('express')
const graphqlHTTP = require('express-graphql')
const { buildSchema } = require('graphql')

const app = express()

const schema = buildSchema(`
  type RandomDie {
    numSides: Int!
    rollOnce: Int!
    roll(numRolls: Int!): [Int]
  }

  type Query {
    getDie(numSides: Int): RandomDie
  }
`)

class RandomDie {
  constructor(numSides) {
    this.numSides = numSides;
  }

  rollOnce() {
    return 1 + Math.floor(Math.random() * this.numSides);
  }

  roll({numRolls}) {
    var output = [];
    for (var i = 0; i < numRolls; i++) {
      output.push(this.rollOnce());
    }
    return output;
  }}

const root = {
  getDie: ({numSides}) => {
    return new RandomDie(numSides || 6);
  },
}

module.exports = root

app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: root,
  graphiql: true,
}))

app.listen(4000)

console.log('Running a GraphQL API server at localhost:4000/graphql')

My random.json file:

{
  "query": "query RollDice($sides: Int) { getDie(numSides: $sides) { rollOnce roll(numRolls: 3) }}",
  "variables": {
    "sides": 6
  }
}

And if I run this command here:

http http://localhost:4000/graphql < ./random.json

I get this output:

{
  "data": {
    "getDie": {
      "roll": [
        1,
        6,
        2
      ],
      "rollOnce": 5
    }
  }
}

My question is this:

How do I set that 3 for numRolls as a variable in the random.json file?

I tried this:

{
  "query": "query RollDice($sides: Int, $rolls: Int) { getDie(numSides: $sides) { rollOnce roll(numRolls: $rolls) }}",
  "variables": {
    "sides": 6,
    "rolls": 3
  }
}

But got this error:

"message": "Variable \"$rolls\" of type \"Int\" used in position expecting type \"Int!\"."


Solution

  • When defining variables, the variable types have to match the types of the inputs they are replacing exactly. While your $rolls variable and the numRolls input type are both integers, you've defined rolls as a nullable integer (Int), while in your schema you've defined the input as a "Non-Null" integer (Int!)

    type RandomDie {
      roll(numRolls: Int!): [Int]
    }
    
    type Query {
      getDie(numSides: Int): RandomDie
    }
    

    Notice that numSides is just an Int while numRolls is defined as a Int!, which is why the ! is not needed for $sides (in fact making $sides an Int! will also throw an error!)

    Non-null is a wrapper that tells GraphQL that the input cannot be null (for input types) or the returned field cannot be null (for data types). The thing to keep in mind is that the non-null wrapper turns the type it wraps into a different type from GraphQL's perspective, so Int !== Int!.