Expert Node.js Support
Learn more

GraphQL

Using GraphQL with MongoDB: graffiti-mongoose

Using GraphQL with MongoDB: graffiti-mongoose

With the Mongoose adapter for Graffiti, you can use your existing Mongoose schema for developing a GraphQL application. If you need an introduction to GraphQL, our previous post helps you to get started with GraphQL.

We are going to cover the following topics:

  • Introduction to Graffiti
  • The Mongoose adapter
  • Relay & GraphQL
  • Getting started with Graffiti
  • Graffiti TodoMVC - a Relay example

Introduction to Graffiti

At RisingStack, we usually don't write boilerplate code. GraphQL is great, but manually specifying the schema can be painful. That's the reason we created Graffiti.
using_graphql_with_mongodb_graffiti_mongoose

Graffiti consists of two main components. You can use graffiti to add a GraphQL endpoint to your web server. Either you can use a schema generated by an adapter, or you can pass in your own. An adapter like graffiti-mongoose can generate the GraphQL schema from your database specific schema description.

The Mongoose adapter for Graffiti

Graffiti currently has an adapter for the Mongoose ORM - with more adapters to come later.

Graffiti Mongoose can help you to use your existing Mongoose schema to generate a Relay compatible GraphQL schema.

We will use the following schema throughout this blog post:

The generated GraphQL schema looks the following:

The road towards Relay compatibility

Relay is a framework for building data-driven React applications. You can declare your data requirements using GraphQL for each component and Relay handles the requests efficiently. Relay makes a few assumptions about the GraphQL schema that is provided by the GraphQL server.

The Node interface

Every type must implement the Node interface, which contains a single id field. This is a globally unique identifier encoding the type and type-specific ID. This makes it possible to re-fetch objects using only the id.

Pagination and the Connection type

The pagination and slicing rely on the standardized Connection type. We can use an introspection query to see what it looks like.

The edge type describes the collection, and the pageInfo contains metadata about the current page. We have also added a count field, which can be very handy in certain situations. Slicing is done via the passed in arguments: first, after, last and before. For example, we could ask for the first two users after a specified cursor on the viewer root field.

Mutations

Mutations like add, update and delete are also supported. Let’s try to add a new user!

As you can see, we just made a typo. We can fix the user’s name by using an update mutation.

Nice, isn’t it?

Resolve hooks

Most likely you'll need some custom logic in your application. For example, to authorize a request or to filter certain fields before returning it to the client. You can specify pre- and post-resolve hooks to extend the functionality of Graffiti Mongoose.
You can add hooks to type fields and query fields (singular & plural queries, mutations) too. By passing arguments to the next function, you can modify the parameters of the next hook or the return value of the resolve function.

For example, this pre-mutation hook filters bad words.

Creating a GraphQL server

First, we need to define our Mongoose models.

We all like pets, right? For our application, we'll keep track of users and pets. Let's define the User and Pet models!

We can generate the GraphQL schema from the Mongoose models using graffiti-mongoose.

Now, we can add graffiti to the project.

Our server is ready to use. You can use GraphiQL, an in-browser GraphQL IDE, to explore our GraphQL API by navigating to localhost:3001/graphql

You can find examples for koa and hapi alongside express in the main repository.

TodoMVC

To demonstrate the Relay compatibility, we also created a Relay application based on the well known TodoMVC. The source code can be found here.

You can take a look here if you want to try it out: http://graffiti-todo.herokuapp.com.


We work hard to make Graffiti and Graffiti Mongoose even better. Recently we did a full rewrite of both projects in ES2015/ES2016 to make the code more readable and easier to make improvements.

If you want to get involved in Graffiti, feel free to contribute to the projects on GitHub.

Start using GraphQL with Graffiti

Update: we've released a Mongoose adapter for Graffiti. Here's how to get started with it.

Currently, the consumption of HTTP REST APIs dominate the client-side world and GraphQL aims to change that. The transition can be time-consuming - this is where Graffiti comes into the picture.

Graffiti grabs your existing models, transforms them into a GraphQL schema and exposes it over HTTP.

Get Graffiti

Why we made Graffiti for GraphQL

We don't want to rewrite our application - no one wants that. Graffiti provides an express middleware, a hapi plugin and a koa middleware to convert your existing models into a GraphQL schema and exposes it over HTTP.

Use cases of Graffiti

There are a couple of areas where Graffiti is extremely useful:

For existing applications

If you are already running an HTTP REST API and uses an ORM then with adding a couple of lines of code you can expose a GraphQL endpoint.

For new applications

Graffiti comes to the rescue when you just about to start developing a new backend for your endpoint consumers - the only thing you have to define is your models using one of the supported ORMs.

Setup Graffiti

Adding to Graffiti to your project is as easy as:

import express from 'express';  
import graffiti from [email protected]/graffiti';  
import {getSchema} from [email protected]/graffiti-mongoose';  
import mongooseSchema from './schema';

const app = express();  
app.use(graffiti.express({  
  schema: getSchema(mongooseSchema)
}));

For complete, working examples check out our Graffiti examples folder.

You can play with a running Relay application using Graffiti here. Navigate to /graphql to explore the schema with GraphiQL.

You can use a GraphQL schema generated by an adapter or your own GraphQLSchema instance with Graffiti.

GraphQL over Websocket / mqtt

With Graffiti you are not limited to HTTP - with the adapters you can easily expose the GraphQL interface over any transport protocol.

Roadmap

We have a fully functional Graffiti adapter for Mongoose and we have plans to support other ORMs too. Also, please note, that some of the following items depend only on the adapters, and not on the main project itself.

  • Query support (done)
  • Mutation support (done)
  • Yeoman generator (planned)
  • Relay support (done)
  • Adapters
    • for MongoDB: graffiti-mongoose (done)
    • for RethinkDB: graffiti-thinky (in progress)
    • for SQL: graffiti-bookshelf (in progress)

Contributing

If you are interested in contributing, just say hi in the main Graffiti repository.

GraphQL Overview - Getting Started with GraphQL and Node.js

We've just released Graffiti: it transforms your existing models into a GraphQL schema. Here is how.

ReactEurope happened last week in the beautiful city of Paris. As it was expected and long-awaited, Facebook released their implementation of the GraphQL draft.

What is GraphQL?

GraphQL is a query language created by Facebook in 2012 which provides a common interface between the client and the server for data fetching and manipulations.

The client asks for various data from the GraphQL server via queries. The response format is described in the query and defined by the client instead of the server: they are called client‐specified queries.
The structure of the data is not hardcoded as in traditional REST APIs - this makes retrieving data from the server more efficient for the client.

For example, the client can ask for linked resources without defining new API endpoints. With the following GraphQL query, we can ask for the user specific fields and the linked friends resource as well.

{
  user(id: 1) {
    name
    age
    friends {
      name
    }
  }
}

In a resource based REST API it would look something like:

GET /users/1 and GET /users/1/friends  


or

GET /users/1?include=friends.name  

GraphQL overview

It's important to mention that GraphQL is not language specific, it's just a specification between the client and the server. Any client should be able to communicate with any server if they speak the common language: GraphQL.

Key concepts of the GraphQL query language are:

  • Hierarchical
  • Product‐centric
  • Strong‐typing
  • Client‐specified queries
  • Introspective

I would like to highlight strong-typing here which means that GraphQL introduces an application level type system. It's a contract between the client and server which means that your server in the background may use different internal types. The only thing here what matters is that the GraphQL server must be able to receive GraphQL queries, decide if that it is syntactically correct and provide the described data for that.

For more details on the concept of GraphQL check out the GraphQL specification.

Where is it useful?

GraphQL helps where your client needs a flexible response format to avoid extra queries and/or massive data transformation with the overhead of keeping them in sync.

Using a GraphQL server makes it very easy for a client side developer to change the response format without any change on the backend.

With GraphQL, you can describe the required data in a more natural way. It can speed up development, because in application structures like top-down rendering in React, the required data is more similar to your component structure.

Check out our previous query and how similar it is to the following component structure:

<App>  
  <User>
    <Friend/>
    <Friend/>
  </User>
</App>  

Differences with REST

REST APIs are resource based. Basically what you do is that you address your resources like GET /users/1/friends, which is a unique path for them. It tells you very well that you are looking for the friends of the user with id=1.

The advantages of REST APIs are that they are cacheable, and their behaviour is obvious.

The disadvantage is that it's hard to specify and implement advanced requests with includes, excludes and especially with linked resources. I think you have already seen requests like:
GET /users/1/friends/1/dogs/1?include=user.name,dog.age

This is exactly the problem what GraphQL wants to solve. If you have types of user and dog and their relations are defined, you can write any kind of query to get your data.

You will have the following queries out of the box:

  • get name of the user with id=1
{
 user(id: 1) {
   name
 }
}
  • get names for friends of the user with id=1
{
 user(id: 1) {
   friends {
     name
   }
 }
}
  • get age and friends of the user with id=1
{
 user(id: 1) {
   age
   friends {
     name
   }
 }
}
  • get names of the dogs of the friends of the user with id=1 :)
{
 user(id: 1) {
   friends {
     dogs {
       name
     }
   }
 }
}

Simple right? Implement once, re-use it as much as possible.

GraphQL queries

You can do two type of queries with GraphQL:

  • when you fetch (get) data from your server and the
  • when you manipulate (create, update, delete) your data

GraphQL queries are like JSON objects without properties:

// a json object
{
  "user": "name"
}
// a graphql query
{
  user {
    name
  }
}

I already showed some queries for getting data from the GraphQL server, but what else can we do?

We can write named queries:

{
  findUser(id: 1)
}

you can pass parameters to your query:

query findUser($userId: String!) {  
  findUser(id: $userId) {
    name
  }
}

With the combination of these building blocks and with the static typing we can write powerful client specified queries. So far so good, but how can we modify our data? Let's see the next chapter for mutations.

GraphQL mutations

With GraphQL mutation you can manipulate data:

mutation updateUser($userId: String! $name: String!) {  
  updateUser(id: $userId name: $name) {
    name
  }
}

With this, you can manipulate your data and retrieve the response in the required format at the same time - pretty powerful, isn't it?

The recommendation here is to name your mutations meaningful to avoid future inconsistencies. I recommend to use names like: createUser, updateUser or removeUser.

GraphQL through HTTP

You can send GraphQL queries through HTTP:

  • GET for querying
  • POST for mutation

Caching GraphQL requests

Caching can work the same way with GET queries, as you would do it with a classic HTTP API. The only exception is when having a very complex query - in that case you may want to send that as a POST and use caching on a database/intermediary level.

Other Transport layers

HTTP is just one option - GraphQL is transport independent, so you can use it with websockets or even mqtt.

GraphQL example with Node.js server

The Facebook engineering team open-sourced a GraphQL reference implementation in JavaScript. I recommend checking their implementation to have a better picture about the possibilities of GraphQL.

They started with the JavaScript implementation and also published an npm library to make GraphQL generally available. We can start playing with it and build a simple GraphQL Node.js server with MongoDB. Are you in? ;)

The GraphQL JS library provides a resolve function for the schemas:

user: {  
  type: userType,
  args: {
    id: {
      name: 'id',
      type: new GraphQLNonNull(GraphQLString)
    }
  },
  resolve: (root, {id}) => {
    return User.findById(id);
  }
}

The only thing what we have to do here is to provide the data for the specific resolve functions. These functions are called by GraphQL JS in parallel.

We can generate a projection for our MongoDB query in the following way:

function getProjection (fieldASTs) {  
  return fieldASTs.selectionSet.selections.reduce((projections, selection) => {
    projections[selection.name.value] = 1;

    return projections;
  }, {});
}

and use it like:

resolve: (root, {id}, source, fieldASTs) => {  
  var projections = getProjection(fieldASTs);
  return User.findById(id, projections);
}

This helps optimising the amount of the fetched data from our database.

Check out the Node.js implementation with MongoDB for more details: https://github.com/RisingStack/graphql-server

Take a look at Graffiti: it transforms your existing models into a GraphQL schema.