Create a simple GraphQL API with Node JS

I used for the first time GraphQL a few days ago and i wanted to share with you what i learned.

In this project, we are going to use GraphQL for one of my favorite Tv Shows : Friends !

11103892_f57d05a21e.jpg

Let's get started

Create a new project

mkdir mygraphQlApi
cd mygraphQlApi
npm init

We are going to use :

  • Koa
npm install koa --save
npm install koa-bodyparser koa-helmet koa-router --save
  • Knex and Knex CLI
npm install knex -g
npm install knex@0.13.0 -g
  • Postgres
npm install pg --save
  • GraphQL
npm install graphql graphql-tools apollo-server-koa --save

Create the Database

We are going to connect to Postgres

sudo -u postgres psql postgres

Then create the database

postgres=# CREATE DATABASE friends;

List your databases to see your new DB just created

postgres=# \list
                                   List of databases
    Name     |  Owner   | Encoding |   Collate   |    Ctype    |   Access privileges   
-------------+----------+----------+-------------+-------------+-----------------------
 friends     | postgres | UTF8     | fr_FR.UTF-8 | fr_FR.UTF-8 | 
 postgres    | postgres | UTF8     | fr_FR.UTF-8 | fr_FR.UTF-8 | 
 template0   | postgres | UTF8     | fr_FR.UTF-8 | fr_FR.UTF-8 | =c/postgres          +
             |          |          |             |             | postgres=CTc/postgres
 template1   | postgres | UTF8     | fr_FR.UTF-8 | fr_FR.UTF-8 | =c/postgres          +
             |          |          |             |             | postgres=CTc/postgres

Finally create a user with a password

CREATE USER myusername WITH PASSWORD 'password';

Connect to your DB

psql -h localhost -d friends -U myusername
Password for user myusername: 


friends=>

Everything is fine !

Type \q to quit.

Back to the project

We are going to create a folder called knex and some subfolders for our seeds, migrations and queries.

mkdir knex
mkdir knex/migrations
mkdir knex/seeds
mkdir knex/queries

Then, to store some data, we are goind to create a folder called data, with a cast.js file inside that folder.

mkdir data
cd data
touch cast.js

Initiate the project

knex init

This command will create a file called knex.js
Let's modify the file like this :

module.exports = {
 development: {
  client: 'pg',
  connection: 'postgres://username:password@localhost:5432/database',
  migrations: {
      directory: __dirname + '/knex/migrations',
    },
    seeds: {
      directory: __dirname + '/knex/seeds'
    }
 }
};

NB : Replace the username, password and database value with the right ones.

Now your project should look like this

Capture d'écran 2021-02-07 18:46:02.png

The Database is empty !

For now, you have a database, but with no data ! Let's fix that !

First , let's create a table on the DB.

knex migrate:make cast
Using environment: development
Created Migration: /path/of/your/project/knex/migrations/20210207185018_cast.js

This command is going to create a migration file, let's modify it like this

exports.up = (knex) => Promise.all([
    knex.schema.createTable('cast', function(table) {
        table.increments();
        table.string('firstName').notNullable();
        table.string('lastName').notNullable();
        table.string('Food').notNullable();
    })
]);

exports.down = (knex) => {
return knex.schema.dropTable('cast');
};

Now let's "run" the migration

knex migrate:latest --env development
Using environment: development
Batch 1 run: 1 migrations

Now that we have a table, let's fill it with some data. We are going to "seed" the table.

knex seed:make cast_seed
Using environment: development
Created seed file:/path/of/your/project/knex/seeds/cast_seed.js

In the data folder, go to your cast.js file and complete it like this :

module.exports = [
    {
      "firstName": "Chandler",
      "lastName": "Bing",
      "Food": "Cheesecake"
    },
    {
        "firstName": "Monica",
        "lastName": "Geller",
        "Food": "Mint Cookies"
    },
    {
        "firstName": "Joey",
        "lastName": "Tribiani",
        "Food": "Pizza"
    }
];

Complete your seed file like this to seed the DB with the data from your file.

const castData = require('../../data/cast');

exports.seed = function(knex) {
  // Deletes ALL existing entries
  return knex('cast').del()
    .then(function () {
      // Inserts seed entries
      return knex('cast').insert(castData);
    });
};

Let's now run this command

knex seed:run --env development
Using environment: development
Ran 1 seed files

Let's connect to the DB, to see our data

psql -h localhost -d friends -U myusername
Password for user myusername: 

friends=> SELECT * FROM public.cast;
 id | firstName | lastName |    Food     
----+-----------+----------+-------------
  1 | Chandler  | Bing     | Cheesecake
  2 | Monica    | Geller   | MintCookies
  3 | Joey      | Tribiani | Pizza
(3 rows)

Congrats, you have now a DB, with a table called cast, and some data in that table!

Next step, the GraphQL part !

GraphQL part

Now let's make the GraphQL part.

Let's create a file called index.js

touch index.js

It should look like this

const Koa = require('koa');
const { ApolloServer, gql } = require('apollo-server-koa');
const queries = require('./knex/queries/queries.js');

const typeDefs = gql`
  type Cast {
    firstName: String
    lastName: String
    Food: String
  }
  type Query {
    cast(firstName: String, lastName: String, Food: String): [Cast]
  }
`;

const schema = {
  typeDefs,
  resolvers: {
    // Prototypes for GET 
    Query: {
      cast: (_, filters) => queries.getCast(filters),
    }
  }
}

const server = new ApolloServer(schema);

const app = new Koa();
server.applyMiddleware({ app });

app.listen({ port: 3000 }, () =>
  console.log(`🚀 Server ready at http://localhost:3000${server.graphqlPath}`),
);

As you can see line 3, we are using queries , let's create them :

In the knex folder, we created a folder called queries. Let's create a file called queries.js

cd knex/queries
touch queries.js
const knex = require('../connect');

function getCast(filters) {
  return knex('cast')
  .select('*')
  .where(filters);
}

module.exports = {
  getCast
};

Let create the connect file used on the first line

cd ../
touch connect.js
const environment = process.env.NODE_ENV || 'development';
const config = require('../knexfile.js')[environment];

module.exports = require('knex')(config);

Now, let's start our server

node index.js
🚀 Server ready at http://localhost:3000/graphql

You should see something like this

Capture d'écran 2021-02-13 19:10:00.png

Query some data

Let's try to query some data

# Write your query or mutation here
query Everyone {
  cast {
    firstName
  }
}

Click on the Play button

{
  "data": {
    "cast": [
      {
        "firstName": "Chandler"
      },
      {
        "firstName": "Monica"
      },
      {
        "firstName": "Joey"
      }
    ]
  }
}

Tadaaaam ! You have made your first query with GraphQL !

Let's add some characters

But wait a minute ... where is Ross ? and Rachel ? And Phoebe ?

We need to add them to our database.

Let's use Mutations for that.

In your index.js file, let's update the schema to add Mutations

# index.js
const typeDefs = gql`
  type Cast {
    firstName: String
    lastName: String
    Food: String
  }
  type Query {
    cast(firstName: String, lastName: String, Food: String): [Cast]
  }
  type Mutation {
  addSomeone(firstName: String, lastName: String, Food: String): [Cast]
}
`;

const schema = {
  typeDefs,
  resolvers: {
    // Prototypes for GET 
    Query: {
      cast: (_, filters) => queries.getCast(filters),
    },
    // Prototypes for PUT
    Mutation: {
        addSomeone: async (_, cast) => {
          const newOne = await queries.addSomeone(cast);

          return newOne;
        }
      }
  }
}

Then in the queries.js file, let's create the actual queries for those mutations.

# queries.js

const knex = require('../connect');

function getCast(filters) {
  return knex('cast')
  .select('*')
  .where(filters);
}

function addSomeone(cast) {
    return knex('cast')
    .insert({
      firstName: cast.firstName,
      lastName: cast.lastName,
      Food: cast.Food
    })
    .returning('*');
}

module.exports = {
  getCast,
  addSomeone
};

Restart our server and write a Mutation to add Ross

mutation addRoss{
  addSomeone(firstName: "Ross", lastName: "Geller", Food: "Turkey Sandwich") {
    firstName
  }
}

Hit the play button

{
  "data": {
    "addSomeone": [
      {
        "firstName": "Ross"
      }
    ]
  }
}

Let's query all the cast once again

# Write your query or mutation here
query Everyone {
  cast {
    firstName
  }
}

Click on play ... and cross fingers

{
  "data": {
    "cast": [
      {
        "firstName": "Chandler"
      },
      {
        "firstName": "Monica"
      },
      {
        "firstName": "Joey"
      },
      {
        "firstName": "Ross"
      }
    ]
  }
}

Yeaaaah ! Now you can add all the others !

Conclusion

I just started learning GraphQL so i probably made some mistakes, i am still figuring out how to make everything work but i wanted to share this first milestone with you !

If you have some tips or resources to help me keep digging the subject, drop them on the comments !

The full code is here on GIthub : Code

Did you find this article valuable?

Support Sonia Manoubi by becoming a sponsor. Any amount is appreciated!