Create a simple GraphQL API with Node JS
Tags: node, graphql, beginners, javascript
Published: 2021-02-14 10:21:43

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](https://cdn.hashnode.com/res/hashnode/image/upload/v1612635511996/XZuDwnrkI.jpeg)

### 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](https://cdn.hashnode.com/res/hashnode/image/upload/v1612719985290/2wykNbT8P.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](https://cdn.hashnode.com/res/hashnode/image/upload/v1613239844589/v40dr3rq1.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](https://github.com/SoniaisMad/graphQL-node)