Categories: Portfolio, Web Dev Training

GraphQL with Node.js and Mongoose/MongoDB

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.

Categories: Software Development

node-oauth-libre 0.9.15 ALPHA

I’m very excited. After starting a fork of node-oauth-libre a month ago, I have implemented a feature that many people have wanted for months: Promises instead of callbacks.

Promises are a way of escaping from Node’s callback hell.

node-oauth-libre now has support for promises thanks to the bluebird library. This support is optional and does not break compatibility with existing uses of node-oauth. To use it, you must explicitly import it.

Click here to check out the release notes for node-oauth-libre 0.9.15 ALPHA. The install and usage instructions are there and a link to some examples.

Here’s an example of using OAuth 1.0 promises:

https://gist.github.com/omouse/0bf79ac1d1edf6a036482e6cb0de9a8f

Categories: Portfolio, Software Development

node-oauth-libre

Update: node-oauth-libre 0.9.15 ALPHA is out, please download and test and report any issues with the new promises support.

In the last month I was looking for a Node.js library for authenticating with APIs that use OAuth 1.0a or OAuth 2.0, and found a pretty good library: node-oauth. It was great but it would have been nicer if it had promises instead of callbacks, and maybe if the OAuth 2 class implemented more methods. I started to worry that the library didn’t seem maintained, there were lots of issues and pull requests that are still waiting for a response or to be merged into the code.

I’ve also been reading Free as in Freedom and The Cathedral and The Bazaar and the hackers of each book, Richard M. Stallman and Eric S. Raymond, both took other projects and improved them and contributed back their changes and improvements to the community. With their maintenance, the projects (Emacs and fetchmail) had vibrant developer and user communities.

So I have decided to basically adopt the node-oauth project under the new name node-oauth-libre. This blog post is the announcement that I’m doing this and yes that means I’ve really forked the code. The node-oauth-libre project uses the GPL version 3, with the original code and patches to the original project licensed under the MIT license.

Continue reading “node-oauth-libre”

Categories: Life

Toronto Node.Js Meetup

8 December, 6:30pm at The Working Group 425 Adelaide W. #300, Toronto, ON.

I’m giving a talk there tonight on using Node.js to construct API Shims that interface between the backend and frontend. It’s going to be good. The basic idea is that frontend code has been decoupled from the backend and mainly relies on REST APIs for communication. NodeJS is probably already used by your build process for the frontend. With that decoupling, the space has been opened up for more Node.js usage, because you can introduce an API shim that sits between the frontend and the backend API. Your API shim can add any missing API calls or it can bundle them up to increase performance or it can do anything else needed to improve your frontend. The most important point of having an API shim is that it further decouples you from the backend especially in terms of release processes so your frontend can be deployed more often than the backend (instead of a bi-weekly process you could deploy daily for example).

Anyway, here’s what the other presenters will be presenting about:

Andrew Carreiro (@arcadeerrorwin), Platform Architect at Klick Health will be presenting ‘Building your own Slack bot on the modern AWS stack’. Hop on the Amazon Web Services hype train and learn how to make a serverless slack bot that runs for pennies per month with NodeJS and Amazon services like Lambda and API Gateway. With just a few steps we’ll be able to enter commands into slack and receive pre defined responses.

Adam Winick, Sr. Web/Mobile developer at Real Matters brings ‘Avoiding callback hell with promises’. He’ll be walking us through the concept of promises in node and presenting a scenario illustrating nested callback overload. Adam will then demonstrated the same scenario (much improved) using promises.

Rudolf Olah (@src_contribute) is a Fullstack Software Developer at CanadaHelps. Rudolf will be speaking about ‘Node.js as an API shim’, giving a tutorial on leveraging Node as an API shim between a java REST API and an AngularJS web app.