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
Top comments (2)
Thanks for the tutorial Aurel Kurtula. You are doing well.
Thanks your tutorial is useful to me and wanna about subscription with related this post