Search code examples
node.jsexpressschemadefinitiongraphql-js

How to formulate nested schema in GraphQL


I am new to GraphQL. As an experiment, I ran the following Node.js Express server:

var express = require('express');
var { graphqlHTTP } = require('express-graphql');
var { buildSchema } = require('graphql');
var schema = buildSchema(`
  type Student {
     sid: ID,
     name: String,
     subjects: [String!],
     address: Location
  }
  type Location{
     unit: String,
     city: String,
     country: String,
     postCode: Int
  }
`);
var root = {   // The root provides a resolver function for each API endpoint
  address: () => ({
    city: ()=>'London'
  }),
};
var app = express();
app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: root,
  graphiql: true,
}));
app.listen(4000);
console.log('Running a GraphQL API server at http://localhost:4000/graphql');

When I ran the following query on the interface on a browser:

{
  address {
     city
  }
}

I got an error:

{
    "errors": [
    {
      "message": "Query root type must be provided."
    }
  ]
}

What should be the correct way of doing this?


Solution

  • It turned out that I must define the schema 'Query' (and optionally 'Mutation') for the entry point.

    var express = require('express');
    var { graphqlHTTP } = require('express-graphql');
    var { buildSchema } = require('graphql');
    
    var fakeDatabase = [{sid:parseInt(Math.random()*10000),
                         name:'Philip',
                         subjects:['Chemistry', 'Physics', 'Maths'],
                         address:{
                               unit: 'H505',
                               city: 'London',
                               country: 'United Kingdom',
                               postCode: 33100
    }}];
    
    // 'Query' and 'Mutation' are special schemas defining the entry points
    var schema = buildSchema(`
      type Query {
         name: String     
         sid(year: Int): ID
         subjects: [String]
         address: Location
      }
      type Location{
         unit: String
         city: String
         country: String
         postCode: Int
      }
      type Mutation{
         setName(nn: String): String
      }
    `);
    
    // Each field is either a constant or a callback
    var root = {
      name: ()=>fakeDatabase[0].name,
      sid: arg => (arg.year+"-"+fakeDatabase[0].sid),
      subjects: fakeDatabase[0].subjects,
      address: () => ({
         city: ()=>fakeDatabase[0].address.city
      }),
      setName: arg => {fakeDatabase[0].name=arg.nn; return arg.nn;}
    };
    
    var app = express();
    app.use('/graphql', graphqlHTTP({
      schema: schema,
      rootValue: root,
      graphiql: true,
    }));
    app.listen(4000);
    console.log('Running a GraphQL API server at http://localhost:4000/graphql');