Adding GraphQL to our Express server

In the previous two posts, we firstly create a basic server, then extended this with REST functionality, now lets add GraphQL capabilities.

First off, run the following

  • yarn add express-graphql graphql
  • Add a folder named schema

With the schema folder add a new file userSchema.ts with the following code

import { buildSchema } from "graphql";

export const schema = buildSchema(`
  type User {
    firstName: String
    lastName: String
  }

  type Query {
    users: [User]
  }
`);

In the above code, we create a GraphQL schema based upon our User type, along with the type Query for us to use the User type.

Next we’ll create a folder named resolvers along with the file userResolver.ts. GraphQL uses resolvers to interact with the data via GraphQL (like the code in the indexController in the previous post).

import { stubData } from "../models/user";

export const userResolver = {
  users: () => {
    return stubData;
  }
}

Now let’s update the server.ts file by adding the GraphQL code, I’ll include the whole file here (at least the specifics for GraphQL)

import graphqlHTTP from "express-graphql";
import { schema } from "./schema/userSchema";
import { userResolver } from "./resolvers/userResolver";

const server = express();

server.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: userResolver,
  graphiql: true,
}));

const port = 4000;
server.listen(port,
  () => console.log(`Server on port ${port}`)
);

In the above we’ve specified graphiql: true which allows us to via the GraphIQL page using http://localhost:4000/graphql

Now if you type the following into the left hand (query) pane

{
  users {
    firstName
    lastName
  }
}

Running this from GraphIQL should output all our stubData.

We’ve essentially got the users method from our original code but now let’s add the equivalent of the create method, which in GraphQL terms is a mutation type.

In the userSchema.ts file, change the schema to look like this

export const schema = buildSchema(`
  type User {
    firstName: String
    lastName: String
  }

  input UserInput {
    firstName: String
    lastName: String
  }

  type Mutation {
    create(user: UserInput): User
  }

  type Query {
    users: [User]
  }
`);

We’ve added an input type UserInput along with the type Mutation. Next, within the userResolve.ts file change the userResolve to add the create function, as below

export const userResolver = {
  users: () => {
    return stubData;
  },
  create: (data: any) => {
    stubData.push(new User(data.user.firstName, data.user.lastName)); 
    return data.user;
  }
}

Let’s test this code by executing the following query via GraphIQL

mutation {
  create(user: {
    firstName: "Miner",
    lastName: "FortyNiner",
  }) {
    firstName
    lastName
  }
}