Quantcast
Channel: Node.js – NeverFriday
Viewing all articles
Browse latest Browse all 6

GraphQL with Node.js and Mongoose/MongoDB

$
0
0

In March 2016, as part of an exploratory project, I worked on an example implementation of GraphQL using MongoDB and Node.js: graphql-server.

While at the time, the company decided not to go with GraphQL, it was only a year later that they revisited the idea and started to make it part of their core technology strategy. They had multiple mobile apps and 3rd party clients that needed a more performant interface than the REST API, which had some performance issues.

My exploratory project turned out to be ahead of its time and a prototype and justification for moving to GraphQL.

Example of a GraphQL Schema

Here’s an example of how to define a schema. The advantage for clients/consumers is that they can select only the fields they need from the API.

import {
  GraphQLObjectType,
  GraphQLNonNull,
  GraphQLSchema,
  GraphQLString,
  GraphQLInt,
  GraphQLList,
  GraphQLID,
  GraphQLBoolean
} from 'graphql/type';
import co from 'co';
import mongoose from 'mongoose';

import models from './models';

var makeGQLString = function(desc) {
  return {
    type: GraphQLString,
    description: desc
  };
};

var makeNonNullGQLString = function(desc) {
  return {
    type: new GraphQLNonNull(GraphQLString),
    description: desc
  };
};

var makeGQLBoolean = function(desc) {
  return {
    type: GraphQLBoolean,
    description: desc
  };
};

var makeGQLInt = function(desc) {
  return {
    type: GraphQLInt,
    description: desc
  };
};

var listingType = new GraphQLObjectType({
  name: 'Listing',
  description: 'An event listing',
  fields: function() {
    return {
      id: makeNonNullGQLString('The id of the listing.'),
      slug: makeNonNullGQLString('slug'),
      title: makeGQLString('The title of the listing.'),
      description: makeGQLString('description'),
      description_html: makeGQLString('description_html'),
      category_id: GraphQLID,
      category_key: makeGQLString('category_key'),
      hashtag: makeGQLString('hashtag'),
      location: makeGQLString('location'),
      website: makeGQLString('website'),
      show_count: makeGQLInt('show count'),
      show_avatars_of_bookers: makeGQLBoolean('show_avatars_of_bookers'),
      show_tickets_sold_count: makeGQLBoolean('show_tickets_sold_count'),
      hide_date: makeGQLBoolean('hide_date'),
      capacity: makeGQLString('Capacity of the listing'),
      state: makeNonNullGQLString('State of the listing')
    };
  }
});

var eventType = new GraphQLObjectType({
  name: 'Event',
  description: 'An event',
  fields: function() {
    return {
      id: makeNonNullGQLString('Event id'),
      start_stamp: makeNonNullGQLString('Start of the event, timestamp'),
      end_stamp: makeNonNullGQLString('End of the event, timestamp'),
      city_name: makeGQLString('Event that the city is in')
    };
  }
});

var rootQueryType =  new GraphQLObjectType({
  name: 'RootQueryType',
  fields: {
    listings: {
      type: new GraphQLList(listingType),
      resolve: function(parent, args, ast) {
        return models.Listing.find().limit(10);
      }
    },
    listing: {
      type: listingType,
      args: {
        id: {
          name: 'id',
          type: new GraphQLNonNull(GraphQLString)
        }
      },
      resolve: function(parent, args, ast) {
        return models.Listing.findOne({ _id: args.id });
      }
    },
    events: {
      type: new GraphQLList(eventType),
      args: {
        listing_id: {
          name: 'listing_id',
          type: new GraphQLNonNull(GraphQLString)
        }
      },
      resolve: function(parent, args, ast) {
        return models.Event.find({ listing_id: args.listing_id });
      }
    }
  }
});

var schema = new GraphQLSchema({
  query: rootQueryType
});

export var getProjection;
export default schema;

We declare a root query that contains certain fields that are resolved by particular functions. The type of each field can be a list, non-null or other types. The resolve function is what fetches data from the database (or whatever caching layer(s) you have).

Within the GraphQLObjectType we can define a structured object with more fields and define the types of those fields. This is in contrast to most REST APIs which provide no schema.

It’s also possible, as you define the fields, to provide descriptions of them. These descriptions can appear in a GraphQL API explorer and since they are built-in and supported as part of the GraphQL specification, the descriptions can be supported by multiple libraries. In contrast, most REST APIs do not place descriptions near the fields within the code; they provide the descriptions (if at all) within separate documentation.

When building this prototype to provide a GraphQL interface to a MongoDB database, it was very easy to declare the schemas for the models and then to provide them as part of the interface.

Click here to see more code for a GraphQL server made with Node, Express and Mongoose.

Want to learn more about GraphQL?

Click here to see a list of 3 excellent videos explaining how GraphQL works.

Here are some questions on GraphQL at StackOverflow:

It is an exciting technology that promises to make it easier for clients to consume APIs and only receive exactly the data that they need.

The post GraphQL with Node.js and Mongoose/MongoDB appeared first on NeverFriday.


Viewing all articles
Browse latest Browse all 6

Latest Images

Trending Articles



Latest Images