nodejs graphql server CRUD example

1. Add the following packages.

npm install apollo-server --save
npm install graphql --save

2. Create some sample data, dummybooks.js

const books = [
  {
    title: 'Harry Potter and the Chamber of Secrets',
    author: 'J.K. Rowling',
  },
  {
    title: 'Jurassic Park',
    author: 'Michael Crichton',
  },
];

for (let i=0; i<1000; i++) {
  books.push({
    title: `Title: ${i}`,
    author: `Author: ${i}`,
  });
}

module.exports = books

3. Define schema for the graphql server in typeDefs.js, this will be the types of objects served by the graphql server.

const { gql } = require('apollo-server');

// A schema is a collection of type definitions (hence "typeDefs")
// that together define the "shape" of queries that are executed against
// your data.
const typeDefs = gql`
  # Comments in GraphQL strings (such as this one) start with the hash (#) symbol.

  # This "Book" type defines the queryable fields for every book in our data source.
  type Book {
    title: String
    author: String
  }

  # The "Query" type is special: it lists all of the available queries that
  # clients can execute, along with the return type for each. In this
  # case, the "books" query returns an array of zero or more Books (defined above).
  type Query {
    books: [Book]
    info: String!
    feed: [Link!]!
    link(id: ID!): Link
  }

  type Mutation {
    # Create a link
    post(url: String!, description: String!): Link!

    # Update a link
    updateLink(id: ID!, url: String, description: String): Link

    # Delete a link
    deleteLink(id: ID!): String
  }

  type Link {
    id: ID!
    description: String!
    url: String!
  }

  type Subscription {
    newLink: Link
  }
`;

module.exports = typeDefs;

4. Create resolvers for the graphql server resolvers.js, this will be the code that handles the requests coming to the graphql server.

const { PubSub } = require('apollo-server');
const books = require('./dummybooks.js');
const pubsub = new PubSub();

const LINK_ADDED = 'LINK_ADDED';

let links = [{
  id: 'link-0',
  url: 'www.howtographql.com',
  description: 'Fullstack tutorial for GraphQL'
}];

let idCount = links.length;

function link(parent, args) {
  console.log("debug Query link received with args: ", args);
  return links.find((link=>link.id === args.id));
}

const Query = {
    info: () => `This is the API of a Hackernews Clone`,
    books: () => books,
    feed: () => links,
    link,
};

const Mutation = {
  post: (parent, args) => {
    console.log("\n\n\ndebug Mutation post received with args: ", args);

    const link = {
      id: `link-${idCount++}`,
      description: args.description,
      url: args.url,
    };

    links.push(link);

    pubsub.publish(LINK_ADDED, { newLink: link });

    return link;
  },
  updateLink: (parent, args) => {
    console.log("\n\n\ndebug Mutation updateLink received with args: ", args);
    const updatedLink = {
      id: args.id,
      description: args.description,
      url: args.url,
    };
    const linkIndex = links.findIndex((link => link.id === updatedLink.id));

    if (linkIndex < 0) {
      throw new Error(`id ${updatedLink.id} not found.`);
    }

    const currentLink = links[linkIndex];
    links[linkIndex] = {
      ...updatedLink
    }

    return links[linkIndex];  

  },
  deleteLink: (parent, args) => {
    console.log("\n\n\ndebug Mutation deleteLink received with args: ", args);
    console.log("debug Mutation deleteLink link size before: ", links.length);
    const linkIndex = links.findIndex((link => link.id === args.id));

    if (linkIndex < 0) {
      throw new Error(`id ${args.id} not found.`);
    }

    links.splice(linkIndex, 1);
    console.log("debug Mutation deleteLink link size after : ", links.length);
    
    return 'deleted.';
  }
};

const Subscription = {
    newLink: {
      // Additional event labels can be passed to asyncIterator creation
      subscribe: () => pubsub.asyncIterator([LINK_ADDED]),
    },
};

// resolvers
module.exports = {
  Query,
  Mutation,
  Subscription,
};

5. Put the server together in index.js, an apollo server and takes the typeDefs and resolvers for the graphql services.

const { ApolloServer } = require('apollo-server');
const typeDefs = require('./typeDefs.js');
const resolvers = require('./resolvers.js');

// The ApolloServer constructor requires two parameters: your schema
// definition and your set of resolvers.
const server = new ApolloServer({ typeDefs, resolvers });

// The `listen` method launches a web server.
server.listen().then(({ url }) => {
  console.log(`🚀  Server ready at ${url}`);
});

Complete example in Github

Search within Codexpedia

Custom Search

Search the entire web

Custom Search