Categories
GraphQL

Adding Mutations with Express GraphQL

Spread the love

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 mutations and input types with Express and GraphQL.

Mutations and Input Types

To create mutations, we create a schema that has the Mutation type rather than a Query .

Then it’s a simple as making the API endpoint part of the top-level Mutation type instead of a Query type.

Both mutations and queries can be handled by root resolvers.

We can then create a GraphQL server that takes both queries and mutations as follows:

const express = require('express');
const graphqlHTTP = require('express-graphql');
const { buildSchema } = require('graphql');
const crypto = require('crypto');
const schema = buildSchema(`
  input TodoInput {
    text: String
  }

  type Todo {
    id: ID!
    text: String
  }

  type Query {
    getTodo(id: ID!): Todo
  }

  type Mutation {
    createTodo(input: TodoInput): Todo
    updateTodo(id: ID!, input: TodoInput): Todo
  }
`);

class Todo {
  constructor(id, { text }) {
    this.id = id;
    this.text = text;
  }
}

let todos = {};

const root = {
  getTodo: ({ id }) => {
    if (!todos[id]) {
      throw new Error('Todo not found.');
    }
    return new Todo(id, todos[id]);
  },
  createTodo: ({ input }) => {
    const id = crypto.randomBytes(10).toString('hex');
    todos[id] = input;
    return new Todo(id, input);
  },
  updateTodo: ({ id, input }) => {
    if (!todos[id]) {
      throw new Error('Todo not found');
    }
    todos[id] = input;
    return new Todo(id, input);
  },
};

const app = express();

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

In the code above, we defined our types by writing:

const schema = buildSchema(`
  input TodoInput {
    text: String
  }

  type Todo {
    id: ID!
    text: String
  }

  type Query {
    getTodo(id: ID!): Todo
  }

  type Mutation {
    createTodo(input: TodoInput): Todo
    updateTodo(id: ID!, input: TodoInput): Todo
  }
`);

We created the input type TodoInput and the Todo type. Then we created the Query type with the getTodo member so that we can get our todo items.

Then in our Mutation , we added the createTodo and updateTodo members so that we can add and update todos.

Then we create our Todo class so that we can store the todo data:

class Todo {
  constructor(id, { text }) {
    this.id = id;
    this.text = text;
  }
}

Next, we have our root resolver:

const root = {
  getTodo: ({ id }) => {
    if (!todos[id]) {
      throw new Error('Todo not found.');
    }
    return new Todo(id, todos[id]);
  },
  createTodo: ({ input }) => {
    const id = crypto.randomBytes(10).toString('hex');
    todos[id] = input;
    return new Todo(id, input);
  },
  updateTodo: ({ id, input }) => {
    if (!todos[id]) {
      throw new Error('Todo not found');
    }
    todos[id] = input;
    return new Todo(id, input);
  },
};

It adds the functions with the same as we specified in our schema so that we can do something when we make some queries.

In this example, getTodo , we’ll return the todo with the given id .The todo that’s found will be returned. Otherwise, we throw an error.

In createTodo , we get the input from the query and then add the todo entry to our todos object, which is our fake database to store the todos. The todo that’s saved will be returned.

Then we have the updateTodo function to update the todo by id . Whatever has the given id will be replaced with the content of input . The todo that’s saved will be returned. We throw an error if a todo with the given id isn’t found.

Then when we go to the /graphql page, we can type in the following to the GraphiQL window:

mutation {
  createTodo(input: {text: "eat"}) {
    id
    text
  }
}

Then we get something like:

{
  "data": {
    "createTodo": {
      "id": "c141d1fda69e8d9084bd",
      "text": "eat"
    }
  }
}

as the response.

If we make a query for updating todo as follows:

mutation {
  updateTodo(id: "e99ce10750c93793a23d", input: {text: "eat"}) {
    id
    text
  }
}

We get something like:

{
  "data": {
    "updateTodo": {
      "id": "e99ce10750c93793a23d",
      "text": "eat"
    }
  }
}

back as the response.

If a todo isn’t found, then we get:

{
  "errors": [
    {
      "message": "Todo not found",
      "locations": [
        {
          "line": 9,
          "column": 3
        }
      ],
      "path": [
        "updateTodo"
      ]
    }
  ],
  "data": {
    "updateTodo": null
  }
}

as the response.

We can make the getTodo query as follows:

query {
  getTodo(id: "e99ce10750c93793a23d"){
    id
    text
  }
}

Then we get:

{
  "data": {
    "getTodo": {
      "id": "e99ce10750c93793a23d",
      "text": "eat"
    }
  }
}

as the response.

Conclusion

We can create mutations as we do with queries.

To accept mutation operations in our GraphQL server, we make our types for storing our data, then we create our mutations by populating the Mutation type with our members.

We can then use the buildSchema function to build the schema we just specified.

Then in our root reducer, we make the functions that with the names that we specified in the type definitions.

Finally, we can make queries to our server to run the mutations.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *