Creating a Basic GraphQL Server with Express

John Au-Yeung - Jan 25 '21 - - Dev Community

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

We can create a simple GraphQL server with Express. To do this, we need the express-graphql and graphql packages.

In this article, we’ll look at how to create a simple GraphQL server with express and make a simple schema for it.

Create an Express GraphQL Server

First, we have to install the packages by running:

npm install express express-graphql graphql --save
Enter fullscreen mode Exit fullscreen mode

Then we can create a server.js file in our project directory and add the following code:

const express = require('express');  
const graphqlHTTP = require('express-graphql');  
const { buildSchema } = require('graphql');
const schema = buildSchema(`  
  type Query {  
    hello: String  
  }  
`);

const root = {  
  hello: () => {  
    return 'Hello world!';  
  },  
};

const app = express();
app.use('/graphql', graphqlHTTP({  
  schema: schema,  
  rootValue: root,  
  graphiql: true,  
}));
app.listen(3000, () => console.log('server started'));
Enter fullscreen mode Exit fullscreen mode

In the code above, we created our express instance, which then we added the schema to it, which we defined by writing:

const schema = buildSchema(`  
  type Query {  
    hello: String  
  }  
`);
Enter fullscreen mode Exit fullscreen mode

With this schema, we’re allowed to submit the hello query to our GraphQL server.

Then we have our root object, which is our resolver for resolving the hello query:

const root = {  
  hello: () => {  
    return 'Hello world!';  
  },  
};
Enter fullscreen mode Exit fullscreen mode

We just return the 'Hello world!' string to the user who queries our server.

The code graphiql: true means that enabled the GraphiQL tool so that we can go to localhost:3000/graphql to see the GraphiQL tool. This is where we can type in our query.

Note that we don’t need a special client to make requests to our client. We can make a POST request to the /graphql endpoint without our GraphQL request payload to send the request to our server.

For example, if we use Postman by typing in our /graphql endpoint and then pass in {“query”: “{ hello }”} as the request payload string. In the header, we set Content/Type to application/json , then we get:

{  
    "data": {  
        "hello": "Hello world!"  
    }  
}
Enter fullscreen mode Exit fullscreen mode

as the response.

We can also make the request in JavaScript with the Fetch API as follows:

(async () => {  
  const response = await fetch(  
    "/graphql",  
    {  
      method: "POST",  
      headers: {  
        "Content-Type": "application/json",  
        Accept: "application/json"  
      },  
      body: JSON.stringify({ query: "{ hello }" })  
    }  
  );  
  const data = await response.json();  
  console.log(data);  
})();
Enter fullscreen mode Exit fullscreen mode

Then we get:

{  
  "data": {  
    "hello": "Hello world!"  
  }  
}
Enter fullscreen mode Exit fullscreen mode

In many cases, we would need to accept arguments in our resolver and query.

To do this, we can write the following:

const express = require('express');  
const graphqlHTTP = require('express-graphql');  
const { buildSchema } = require('graphql');  
const schema = buildSchema(`  
  type Query {  
    rollDice(numSides: Int): Int  
  }  
`);

const root = {  
  rollDice: (params) => {  
    const { numSides } = params;  
    return Math.ceil(Math.random() * numSides);  
  },  
};

const app = express();
app.use('/graphql', graphqlHTTP({  
  schema: schema,  
  rootValue: root,  
  graphiql: true,  
}));
app.listen(3000, () => console.log('server started'));
Enter fullscreen mode Exit fullscreen mode

In the code above, we have the root object with the rollDice resolver function which as the params parameter to get the arguments that are passed into GraphQL request.

Then we return a random number from it and return it. The number will be returned within the response.

To make our rollDice resolver accept the request, we included:

type Query {  
  rollDice(numSides: Int): Int  
}
Enter fullscreen mode Exit fullscreen mode

in our schema so that it’ll take in the numSides argument.

If we go to the /graphq page in our browser, and then type in:

{  
  rollDice(numSides: 10)  
}
Enter fullscreen mode Exit fullscreen mode

in the left pane, we’ll get a number between 0 and 10.

To make a GraphQL POST request that takes in arguments, we can write the following:

(async () => {  
  const numSides = 6;  
  const query = `query RollDice($numSides: Int) {  
   rollDice(numSides: $numSides)  
  }`; 

  const response = await fetch(  
    "/graphql",  
    {  
      method: "POST",  
      headers: {  
        "Content-Type": "application/json",  
        Accept: "application/json"  
      },  
      body: JSON.stringify({  
        query,  
        variables: { numSides },  
      })  
    });  
  const data = await response.json();  
  console.log(data);  
})();
Enter fullscreen mode Exit fullscreen mode

In the code above, we have the query , which is:

query RollDice($numSides: Int) {  
  rollDice(numSides: $numSides)  
}
Enter fullscreen mode Exit fullscreen mode

and variables , which is:

variables: { numSides }
Enter fullscreen mode Exit fullscreen mode

The JSON body that we sent with the request is:

{  
  "query": "query RollDice($numSides: Int) {  
     rollDice(numSides: $numSides)  
  }",  
  "variables": {  
    "numSides": 6  
  }  
}
Enter fullscreen mode Exit fullscreen mode

This is the same what we ran in the GraphiQL UI, but needed the query RollDice to wrap our query so that we can pass in the numSides variable.

Conclusion

We can easily create a GraphQL Server with Express by using the express-graphql package.

After that, we have to create our resolver function and schema to let us accept GraphQL requests.

Resolvers can also accept variables. In there, we return the result, which will then be returned in the response to the user.

To test our API, we can use the GraphiQL GUI to enter queries and test them.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .