Learn Graphql by building an API for a to-do app.
Tags: graphql, node, beginners, tutorial
Published: 2020-02-06 16:04:08


Welcome, this tutorial guides you through building a Todo Graphql-powered API with Node.js and MongoDB.

## Getting Started

What you will learn:

* Obtain a basic understanding of GraphQL principles
* Define a GraphQL **schema** that represents the structure of your data set
* Build an API with Apollo-Server that lets you execute queries against your schema

**_Requirements_**

This tutorial assumes that you are familiar with the command line and
JavaScript/ES6, and that you have a recent version of Node.js (8+) and `npm` || `yarn` installed.

## Step 1: Create a new project

1. Create a directory for a new project and `cd` into it:

    ```bash
    mkdir graphql-todo-server
    cd graphql-todo-server
    ```

2. Initialize a new Node.js project with `yarn` or `npm`:

    ```bash
    yarn init --yes
    ```

Your project directory now contains a `package.json` file.

## Step 2: Install dependencies

To run Apollo-Server, we need to install `apollo-server`, `graphql`. Also we need to install `mongoose` to connect to DB and create our model:

* [`apollo-server`](https://npm.im/apollo-server) is the core library for Apollo Server itself, which helps you define the shape of your data and how to fetch it.
* [`graphql`](https://npm.im/graphql) is the library used to build a GraphQL schema and execute queries against it.
* [`mongoose`](https://mongoosejs.com/) provides a straight-forward, schema-based solution to model your application data.

Run the following command to install these dependencies and save them in
your project's `node_modules` directory:

```bash
yarn install apollo-server graphql mongoose
```

Also, create the following for a better project structure:

```bash
touch index.js

mkdir graphql models
```

* index.js is our entry for our server
* graphql directory will hold our typeDef and resolvers
* model for our mongodb models

## Step 3: Build a Schema

Every data graph uses a schema to define the types of data it includes.
_first_, we will create a file typeDefs.js which will hold our shcema inside our graphql directory

```bash
    cd graphql
    touch typeDefs.js
```

Now, the schema will look like this:

```javascript
const { gql } = require("apollo-server");

module.exports = gql`
  type Todo {
    id: ID!
    body: String!
    created: String!
  }

  type Query {
    getTodos: [Todo]!
  }

  type Mutation {
    createTodo(body: String!): Todo!
    deleteTodo(todoId: ID!): String!
   }
`;

```

We are exporting our [`Schema`](https://www.apollographql.com/docs/apollo-server/getting-started/#step-3-define-your-graphql-schema) to use it in `index.js` when creating our server, Our Todo is very simple:

The `type Todo`, defines our todo object's fields:

* id: every Todo will have a unique id that Mongogb will create for us.
* body: of type string for our todo text.
* created: will hold the date.
* The **`!`** after each type means it can not be null

The [`Query`](https://www.apollographql.com/docs/tutorial/schema/#the-query-type) type
> our schema needs to define queries that clients can execute against the data graph.

The [`Mutation`](https://www.apollographql.com/docs/tutorial/schema/#the-mutation-type) type
> with the query, we can fetch the data, but not to modify it. our schema needs to define mutations to modify our data.

The [`gql`](https://www.apollographql.com/docs/apollo-server/api/apollo-server/#gql) tag
> the gql tag is used to surround GraphQL operation and schema language (which are represented as Strings), and makes it easier to differentiate from ordinary strings.

## Step 4: Create our Todo model

```javascript
const { model, Schema } = require("mongoose");

const todoSchema = new Schema({
  body: String,
  created: String
});

module.exports = model("Todo", todoSchema);

// Note: the id will be generated automatically
```

## Step 5: Define the resolvers

We've defined the shape of our data, but Apollo doesn't know how to fetch it. To fix this, we create a resolver.
First, we create the file in graphql

```bash
touch graphql/resolvers.js
```

Now, our resolvers will look like this:

```javascript
// we need a Todo model in our mutations to modify the data.
const Todo = require('../models/Todo');

module.exports = {
  Query: {
    // here is the getTodos, that we defined in our typeDefs.
    // simply, using the Todo model to fetch all the todos with async/await
    // and return the result.
    async getTodos() {
      try {
        const todos = await Todo.find({}).sort({ created: -1 });
        return todos;
      } catch (err) {
        throw new Error(err);
      }
    }
  },

  Mutation: {
      async createTodo(_, { body }) {
    // destructure the body from our args.
    // create a new Todo, save and return that todo
    // created is the date.
      try {
        const newTodo = new Todo({
          body,
          created: new Date().toISOString()
        });
        const todo = await newTodo.save();
        return todo;
      } catch (err) {
        throw new Error(err);
      }
    },

    async deleteTodo(_, { todoId }) {
      // Find the todo by its Id and delete it.
      try {
        const todo = await Todo.findById(todoId);
        if (todo) {
            await todo.delete();
            return 'Todo deleted!';
        } else {
            return 'Todo does not exist'
        }
      } catch (err) {
        throw new Error(err);
      }
    }
  }
};
```

Again!, we exporting the `resolvers` to use it when creating the Apollo Server.
The `resolver` takes a couple of positional arguments (parent,args,context,info). for our app we need only the `args`, for more info, read [`Resolvers type signature`](https://www.apollographql.com/docs/apollo-server/data/data/#resolver-type-signature).

## Step 6: Create the Apollo Server

finally, We create our server and connect to the db.

```javascript
const { ApolloServer } = require('apollo-server');
const mongoose = require('mongoose');

// The config file contains any project configuration
// MONGODB will be something like this "'mongodb://username:password@host:port/database?options...'", you can get your own from Mongodb.com.
// PORT: process.env.PORT || '5000', if no env variables.

const { MONGODB ,PORT } = require('./config');

const typeDefs = require('./graphql/typeDefs');
const resolvers = require('./graphql/resolvers');

const server = new ApolloServer({
  typeDefs,
  resolvers
});

mongoose
  .connect(MONGODB, {
    useUnifiedTopology: true,
    useNewUrlParser: true
  })
  .then(() => {
    console.log('MongoDB is connected ...');
    return server.listen({
      port: PORT
    });
  })
  .then(res => {
    console.log('Server running at ', res.url);
  });


```

Now, you can run your server by running this command.

```bash
node index.js
 ```

 To re-run the server automatically when a file changes. you can install nodemon package globally. and then use it in your project.

```bash
npm install -g nodemon

nodemon index.js
```

your terminal will be like this if no errors.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/grc8b794j3mziq0qmz6t.png)

Tada, that's it, I hope you find it helpful and please comment below if you have any questions.
Have A Great Day!