In this tutorial, we will walk through the process of creating a GraphQL server using Node.js and Express. By the end of this guide, you will have a basic understanding of how to set up a GraphQL server that can handle queries and mutations.
Start by creating a new Node.js project if you haven’t done so already:
npm init --y
This command will create a package.json
file, which is necessary for working with npm packages.
Next, install the required npm packages: express
, graphql
, and express-graphql
:
npm install express graphql express-graphql
Now, let’s create the app.js
file and start by initializing the Express server:
const express = require('express')
const app = express()
app.listen(3000, () => {
console.log('App listening on port 3000')
})
To add GraphQL functionality, we need to include the express-graphql
middleware. We will apply this middleware to a specific route, in this case, the /graphql
route:
const express = require('express')
const graphqlHTTP = require('express-graphql')
const app = express()
app.use('/graphql', graphqlHTTP())
app.listen(3000, () => {
console.log('App listening on port 3000')
})
Before we move forward, we need to define the schema for our GraphQL server. Let’s create a schema.js
file and require the necessary objects from the graphql
package:
const graphql = require('graphql')
const { GraphQLSchema, GraphQLObjectType, GraphQLString } = graphql
Next, we’ll define the schema by initializing a new GraphQLSchema
instance. This instance should have a query
property, which is an instance of a GraphQLObjectType
object:
const schema = new GraphQLSchema({
query: new GraphQLObjectType({
//...
}),
})
module.exports = schema
Inside the query
object, we must specify a name
and a fields
property. The fields
property is an object that contains a set of properties, one for each field in our schema. Let’s set up a simple hello
field:
const schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'RootQueryType',
fields: {
hello: {
type: GraphQLString,
resolve() {
return 'world'
},
},
},
}),
})
In this example, the resolve()
method returns the string 'world'
, which means that when we ask for the hello
field, we’ll get that string in response.
Here is the content of the complete schema.js
file:
const graphql = require('graphql')
const { GraphQLSchema, GraphQLObjectType, GraphQLString } = graphql
const schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'RootQueryType',
fields: {
hello: {
type: GraphQLString,
resolve() {
return 'world'
},
},
},
}),
})
module.exports = schema
Now, let’s go back to our app.js
file. We need to require the schema.js
file and add it to the graphqlHTTP
constructor:
const schema = require('./schema.js')
app.use(
'/graphql',
graphqlHTTP({
schema: schema,
})
)
With this configuration, we can now test our GraphQL API using GraphiQL, a tool for testing GraphQL APIs. To enable GraphiQL, we need to pass an additional property to the graphqlHTTP
constructor:
app.use(
'/graphql',
graphqlHTTP({
schema: schema,
graphiql: true,
})
)
After running node app.js
, you can access the http://localhost:3000/graphql
URL in the browser to see GraphiQL in action. You can test the first API call by passing the following query:
{
hello
}
The result should be:
{
"data": {
"hello": "world"
}
}
Now, let’s build a more complex schema that includes nested types. We’ll use a blog post example where each post has a title, description, and an author. The author has a name.
First, let’s define the posts and authors data:
const posts = [
{
title: 'First post',
description: 'Content of the first post',
author: 'Flavio',
},
{
title: 'Second post',
description: 'Content of the second post',
author: 'Roger',
},
]
const authors = {
Flavio: {
name: 'Flavio',
age: 36,
},
Roger: {
name: 'Roger',
age: 7,
},
}
Next, we’ll define three GraphQLObjectType
instances:
authorType
, which defines the author datapostType
, which defines the post dataqueryType
, the main type
Let’s start with the authorType
. An author has a name and an age:
const authorType = new GraphQLObjectType({
name: 'Author',
fields: {
name: {
type: GraphQLString,
},
age: {
type: GraphQLInt,
},
},
})
Next is the postType
. A post has a title, a description (both strings), and an author. The author
field is of type authorType
, which we just defined. We also need to provide a resolver function for the author
field. In this case, we retrieve the author data from the authors
object based on the author
property of the source:
const postType = new GraphQLObjectType({
name: 'Post',
fields: {
title: {
type: GraphQLString,
},
description: {
type: GraphQLString,
},
author: {
type: authorType,
resolve: (source, params) => {
return authors[source.author]
},
},
},
})
Lastly, we create the queryType
, which is the root type that will be added to the schema. It includes two fields:
post
, which retrieves a single blog post identified by anid
posts
, which retrieves the list of posts
Both fields have a resolver function that retrieves the data from the posts
array:
const queryType = new GraphQLObjectType({
name: 'Query',
fields: {
post: {
type: postType,
args: {
id: { type: GraphQLInt },
},
resolve: (source, { id }) => {
return posts[id]
},
},
posts: {
type: new GraphQLList(postType),
resolve: () => {
return posts
},
},
},
})
Here, we use the GraphQLList
type to indicate that posts
is a list of postType
objects.
Finally, we add the queryType
to our schema
:
const schema = new GraphQLSchema({
query: queryType,
})
The complete code is as follows:
const graphql = require('graphql')
const {
GraphQLSchema,
GraphQLObjectType,
GraphQLString,
GraphQLList,
GraphQLInt,
} = graphql
const posts = [
{
title: 'First post',
description: 'Content of the first post',
author: 'Flavio',
},
{
title: 'Second post',
description: 'Content of the second post',
author: 'Roger',
},
]
const authors = {
Flavio: {
name: 'Flavio',
age: 36,
},
Roger: {
name: 'Roger',
age: 7,
},
}
const authorType = new GraphQLObjectType({
name: 'Author',
fields: {
name: {
type: GraphQLString,
},
age: {
type: GraphQLInt,
},
},
})
const postType = new GraphQLObjectType({
name: 'Post',
fields: {
title: {
type: GraphQLString,
},
description: {
type: GraphQLString,
},
author: {
type: authorType,
resolve: (source, params) => {
return authors[source.author]
},
},
},
})
const queryType = new GraphQLObjectType({
name: 'Query',
fields: {
post: {
type: postType,
args: {
id: { type: GraphQLInt },
},
resolve: (source, { id }) => {
return posts[id]
},
},
posts: {
type: new GraphQLList(postType),
resolve: () => {
return posts
},
},
},
})
const schema = new GraphQLSchema({
query: queryType,
})
module.exports = schema
You can find the complete code on Glitch.
Tags: GraphQL, Node.js, Express, Schema, Query, Mutation