Playing with GraphQL yoga and mongoose

aurelkurtula

aurel kurtula

Posted on December 22, 2018

Playing with GraphQL yoga and mongoose

This is going to be an introduction to using GraphQL yoga, which is a GraphQL server based on Express.

If you don't know what GraphQL is, you might want to go through my previous tutorial where I use Express and GraphQL. That should get you up to speed. You could then learn how you can create a movie website with GraphQL and React but not really required for you to understand this. We're simply recreating the first tutorial with different tooling.

Get started

Let's set up the basic project. In an empty directory run these command lines

npm init -y
npm i -S graphql-yoga mongoose
touch index.js

The first line sets up the npm project, the second line installs the only two packages we will need, and to keep things simple, the entire code is going to go in index.js. Let's create a very basic structure:

const { GraphQLServer } = require('graphql-yoga');

const typeDefs = `
type Query {
  Greeting: String
}
`
const resolvers = {
  Query: {
    Greeting: () => `Hello World`
  }
}
const server = new GraphQLServer({
  typeDefs,
  resolvers
})

server.start({port: 7777}, () => console.log(`The server is running on port 7777`))

We required graphql-yoga at the top and run the server at the bottom. A GraphQL server needs us to define the type of queries it will be running, and the kind of data each query will respond with.

In our simple version, we have a query of Greeting that will return a string. And we specify that when the Greeting is called Hello World will be returned.

Now, all we're left to do is run this in the terminal node index.js. I highly recommend you install nodemon but that's beyond the point.

Now you need to run http://localhost:7777 in a graphql playground or use an online graphql playground. Then just run the following query:

{
  Greeting
}

And you'll get the response Hello World.

A bit deeper

Let's add an array of objects

const typeDefs = `
type Query {
    People: [PeopleObject]!
    Greeting: String
}
type PeopleObject {
    id: ID
    first: String!
    last: String!
}
`
const resolvers = {
  Query: {
    Greeting: () => `Hello World`,
    People: () => [{first: 'Aurel', last: 'Kurtula'}]
  }
}

We've added People as a possible query. It has to return an array of objects, the properties of the object are defined in PeopleObject. Note the use of ! makes those properties as required - meaning we have to return that content.

Then we hard-coded an array which will be returned.

In the playground, we could run this

{
  Greeting
  People{
    first
    last
  }
}

Connecting to mongo database

In a previous tutorial I go through creating a mongo database from mlab. So follow that if you don't already have mongodb installed locally or if you don't know how to set up a mongo database. Then come back, still in index.js at the top add the following code.

const mongoose = require('mongoose');
const db = mongoose.connect('mongodb://localhost:27017/population');
const Schema = mongoose.Schema;
const peopleSchema = new Schema({
    first: { type: String  },
    last: { type: String}
})
const People = mongoose.model('people', peopleSchema)

If you have mongodb installed and running locally, the above would work out as is, if not you'll need to change the url which mongoose should connect to. population will be created automatically. Then we create a schema. Similar to what we did with Graphql, we need to tell mongoose what type of content will be added to the model, then we specify the model.

From this point forward, as you'll see, we interact only with the People model and the people model in the population database will be affected.

Mongo and GraphQL

When we query People in the GraphQL playground we want the data to come from the mongo database and not from the array we hard coded. So let's change the resolvers

const resolvers = {
  Query: {
    Greeting: () => `Hello World`,
    People: () => People.find({}),
  }
}

There we are returning all the entries from the model in the database.

Cleary if we rerun the query in the playground we would get an empty array for People query as there's nothing in the database.

Now we need to add to the database through GraphQL. For this we need to use mutations:

const typeDefs = `
type Query {
  people: [People!]!
  person(id: ID!): People
}
type People {
    id: ID
    first: String
    last: String
}
type Mutation {
    createPerson(first: String!, last: String!): People
}
`

First, we specify the type; a mutation named createPerson it requires two properties and will return the People object. As usual, we need to specify the results of running that mutation, in resolvers

const resolvers = {
  Query: {....},
  Mutation: {
    createPerson: async (parent, args) =>{
        const newPerson = new People({
            first: args.first,
            last: args.last
        })
        const error = await newPerson.save()

        if(error) return error 
        return newPerson
    }
  }
}

Similar to other resolvers we want to do something when createPerson runs. This time we need to have access to the variables passed by the user, hence args (parent is beyond the scope of this tutorial).

First we create the newPerson object which we want to add to the database, then we create a new People module populated with the newPerson object, and finally, we save the object to the database, then we simply return the newly created object to graphQL server.

Back to the GraphQL playground

query people {
  Greeting
  People{
    first
    last
  }
}
mutation addingPerson{
  createPerson(first: "Gregor", last: "Samsa"){
    first
    last

  }
}

There, if you want to run the mutation you run addingPerson (by the drop-down menu). And, of course, after you add Gregor you can see the bugger :) when you run the people query.

Finally, let's follow the same logic and add the ability to remove a person from the database.

First, specify the type deletePerson:

type Mutation {
    createPerson(first: String!, last: String!): PeopleObject
    deletePerson(id: ID!): PeopleObject
}

Then let's resolve it as yet another mutation:

const resolvers = {
  ...
  Mutation: {
    createPerson: (parent, args) =>{...},
    deletePerson: (parent, args) => {
        return new Promise( (resolve, reject) => {
            People.findOneAndDelete(args.id, function(err, result){
                if (err) return err;
                resolve(result)
            })
        })
    }
  }

}

It's the exact same logic, mongoose gives us the ability to delete an object by its id - using findOneAndDelete. You can test deletePerson as follows:

mutation deleting{
  deletePerson(id: "5c1ccc3de652317c2c79d4ee"){
    first
    last
  }
}

And that is it for this tutorial.

You can get the code over at github. The code is divided into different files as it would in a fleshed out project

💖 💪 🙅 🚩
aurelkurtula
aurel kurtula

Posted on December 22, 2018

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Playing with GraphQL yoga and mongoose
graphql Playing with GraphQL yoga and mongoose

December 22, 2018