How to Create a Note-taking App with Appwrite and GraphQL in Next.js 13
Published: 2023-02-24 09:37:38

Taking notes is one of the most common and preferred methods of documenting and noting key points, whether taking classes or attending a meeting.

This article will teach us how to build a Note-taking app using [Appwrite](https://appwrite.io/?utm_source=hackmamba&utm_medium=blog&utm_campaign=hackmamba), [GraphQL](https://graphql.org/), and [Next.](https://nextjs.org/)[js](https://nextjs.org/).

## Prerequisites

To get the guides highlighted in the technical guide, we need to have the following:


To get the guides highlighted in the technical guide, we need to have the following:


- [Docker](https://docs.docker.com/get-docker/) and [Node](https://nodejs.org/en/)[.js](https://nodejs.org/en/) installed
- Basic understanding of [React](https://beta.reactjs.org/)[.js](https://beta.reactjs.org/) and [Next](https://nextjs.org/)[.js](https://nextjs.org/)

## Setting Up Appwrite

Appwrite is a backend-as-a-service platform that gives developers the power to create fully functional backend applications without worrying about the underlying infrastructure or services.

To setup Appwrite on our local development environment, ensure that docker is installed and run the following commands:

Unix 

```bash
    docker run -it --rm \
        --volume /var/run/docker.sock:/var/run/docker.sock \
        --volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
        --entrypoint="install" \
        appwrite/appwrite:1.2.0
```

Windows Command Prompt (CMD)


```bash
    docker run -it --rm ^
        --volume //var/run/docker.sock:/var/run/docker.sock ^
        --volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^
        --entrypoint="install" ^
        appwrite/appwrite:1.2.0
```

Powershell


```bash
    docker run -it --rm `
        --volume /var/run/docker.sock:/var/run/docker.sock `
        --volume ${pwd}/appwrite:/usr/src/code/appwrite:rw `
        --entrypoint="install" `
        appwrite/appwrite:1.2.0
```

The command will prompt the following configurations:

```bash
    Choose your server HTTP port: (default: 80): <PRESS ENTER>/port number of choice
    Choose your server HTTPS port: (default: 443): <PRESS ENTER>
    Choose a secret API key, make sure to make a backup of your key in a secure location (default: 'your-secret-key'): <PRESS ENTER>
    Enter your Appwrite hostname (default: 'localhost'): <PRESS ENTER>
    Enter a DNS A record hostname to serve as a CNAME for your custom domains.
    You can use the same value as used for the Appwrite hostname. (default: 'localhost'): <PRESS ENTER>
```

![image](https://paper-attachments.dropboxusercontent.com/s_D8DF24E69B6961169A9CFA34377755DCFEE181868E275886A4D520907BD1998A_1674668712420_image.png)


After a successful installation, Appwrite will run on localhost on the port number set during configuration. By default, it runs on port 80: **localhost:80**. In the demo, the port was configured to 5000: **localhost:5000**

Run localhost on the port configured during installation. We will be redirected to the authentication page. To create an account, use the URL: **http://localhost:5000/register**

![image](https://paper-attachments.dropboxusercontent.com/s_D8DF24E69B6961169A9CFA34377755DCFEE181868E275886A4D520907BD1998A_1674673667698_image.png)

## Creating an Appwrite Project

After successful authentication, we will be redirected to a new page to create a new project:


![image](https://paper-attachments.dropboxusercontent.com/s_D8DF24E69B6961169A9CFA34377755DCFEE181868E275886A4D520907BD1998A_1674673898639_image.png)


Enter a project name; for this demo, we will use “notes”. After creating the project, we will get to the project dashboard.


![image](https://paper-attachments.dropboxusercontent.com/s_D8DF24E69B6961169A9CFA34377755DCFEE181868E275886A4D520907BD1998A_1674675083414_image.png)


## Creating a Database and a Collection

Click on `Create database` to create a new database.


![image](https://paper-attachments.dropboxusercontent.com/s_D8DF24E69B6961169A9CFA34377755DCFEE181868E275886A4D520907BD1998A_1674675239977_image.png)


After creating a database, we will need to create a collection. We can do this by clicking on the `Create collection` button.


![image](https://paper-attachments.dropboxusercontent.com/s_D8DF24E69B6961169A9CFA34377755DCFEE181868E275886A4D520907BD1998A_1674675338692_image.png)


To start adding data to our collection, we need to set attributes. Inside the `notes_collection`, click on the `Attributes` tab to add the following attributes:


- title
- notes

NOTE: While creating the attributes, we are required to define the attribute’s data type and size.


![image](https://paper-attachments.dropboxusercontent.com/s_D8DF24E69B6961169A9CFA34377755DCFEE181868E275886A4D520907BD1998A_1674675800523_image.png)


After creating the required attributes, click on the document tab to add dummy data.


![image](https://paper-attachments.dropboxusercontent.com/s_D8DF24E69B6961169A9CFA34377755DCFEE181868E275886A4D520907BD1998A_1674675951214_image.png)



## Creating a Next.js Application

To create a Next.js application, run the following command on a command line tool:

`npx create-next-app notes-app`

After a successful installation, we can run the project with the following commands to confirm a successful setup:

```bash
    cd notes-app
    npm run dev
```

Next.js will run locally on port 3000: localhost:3000.

For the demo, the user design is already set up and can be found on [GitHub](https://github.com/achingachris/Note-Taking-Application-NextJS/tree/layout):

{% embed https://github.com/achingachris/Note-Taking-Application-NextJS/ %}


Clone the repository for a smooth code along through the article.

```bash
    git clone https://github.com/achingachris/Note-Taking-Application-NextJS.git
```


After cloning, install the node packages by running:

```bash
    npm install
```

To run the application, use the following command:


```
    npm run dev
```

The project will run on localhost:3000

![image](https://paper-attachments.dropboxusercontent.com/s_D8DF24E69B6961169A9CFA34377755DCFEE181868E275886A4D520907BD1998A_1676235356172_image.png)



## Breaking down the Next.js Application

All of the notes taken will be displayed in a list, as defined in the `NoteItem` component:


```javascript
    const NoteItem = ({ title, notes }) => {
      return (
        <div className='card mb-3'>
          <div className='card-header'>{title}</div>
          <div className='card-body'>
            <p className='card-text'>{notes}</p>
          </div>
        </div>
      )
    }
    export default NoteItem
    NoteItem.defaultProps = {
      title: 'Note Title',
      notes:
        'With supporting text below as a natural lead-in to additional content.',
    }
```


To add a note, we will create a form using the `AddNoteForm` component:


```javascript
    const AddNoteForm = ({newTitle, newNote}) => {
      return (
        <div className='m-2'>
          <form>
            <div className='mb-3'>
              <label htmlFor='title' className='form-label'>
                Title
              </label>
              <input
                type='text'
                className='form-control'
                id='title'
                placeholder='Note Title'
              />
            </div>
            <div className='mb-3'>
              <label htmlFor='note' className='form-label'>
                Text
              </label>
              <textarea
                className='form-control'
                id='note'
                rows={3}
                defaultValue={''}
              />
            </div>
            <button type='submit' className='btn btn-primary'>
              Add Note
            </button>
          </form>
        </div>
      )
    }
    export default AddNoteForm
```


## Using GraphQL & Appwrite's GraphQL

[Appwrite's GraphQL API](https://appwrite.io/docs/graphql?utm_source=hackmamba&utm_medium=blog&utm_campaign=hackmamba) is a tool for building APIs that allows clients to request only the data they need and nothing more, making it more efficient and flexible than traditional REST APIs. 

Through the endpoint `/v1/graphql`, we can query and modify any resource type on our Appwrite server. Except for OAuth, every REST endpoint is available via GraphQL.

We can setup up the GraphQL playground locally to test for Appwrite’s GraphQL APIs. To do so, create a file with a `.sh` extension, i.e., `appwrite-grapghql.sh,` and copy the following:

```bash
    #!/bin/sh
    
    # To ensure the GraphQL docs load in the explorer, set the _APP_OPTIONS_ABUSE
    # variable to disabled in your .env file.
    # 
    # If you have a domain, run this script passing the endpoint like:
    #   ./start-appwrite-graphql-explorer.sh https://appwrite.example.com/v1
    #
    # After you see "GraphQL Explorer listening on port 3000!", open your browser
    # and browse to http://localhost:3000/
```


![image](https://paper-attachments.dropboxusercontent.com/s_D8DF24E69B6961169A9CFA34377755DCFEE181868E275886A4D520907BD1998A_1676715205712_image.png)


The script will run GraphQL on port 3000: http://localhost:3000/


![image](https://paper-attachments.dropboxusercontent.com/s_D8DF24E69B6961169A9CFA34377755DCFEE181868E275886A4D520907BD1998A_1675057222929_image.png)


## Integrating Appwrite with Next.js using GraphQL

To start using Appwrite’s GraphQL, we will need to install the `[appwrite](https://www.npmjs.com/package/appwrite)` node module.

```bash
    npm i appwrite
```

A configuration of Appwrite’s web SDK using GraphQL is shown below:


```javascript
    import { Client, Graphql } from "appwrite";
    
    const client = new Client()
        .setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your Appwrite Endpoint
        .setProject('[PROJECT_ID]');                // Your project ID
    
    const graphql = new Graphql(client);
    
    const mutation = graphql.post({
        query: `mutation CreateAccount(
            $email: String!,
            $password: String!,
            $name: String
        ) {
            accountCreate(
                email: $email,
                password: $password,
                name: $name
            ) {
                _id
            }
        }`,
        variables: {
            email: '...',
            password: '...',
            name: '...'
        }
    });
    
    mutation.then(response => {
        console.log(response);
    }).catch(error => {
        console.log(error);
    });
    
```

**Explanation of the Snippet Above:**

1. Importing the `Client` and `GraphQL` classes from the `appwrite` library will make it possible to use Appwrite’s GraphQL features in our web application.
2. We then create a new Client instance where we set the Appwrite configurations by setting the endpoint and project ID for the Appwrite server. In this case, we will use:

```javascript
    const client = new Client()
        .setEndpoint('https://localhost:5000/v1/graphql') // Your Appwrite Endpoint
        .setProject('[PROJECT_ID]')
```

To get the project ID, go to the project view on the Appwrite console and click on `Settings` to get the ID:

![image](https://paper-attachments.dropboxusercontent.com/s_D8DF24E69B6961169A9CFA34377755DCFEE181868E275886A4D520907BD1998A_1675058519034_image.png)
3.We then create a new instance of the `Graphql` class, passing the `Client` instance as a parameter.


## Getting Notes from Appwrite

We then modify our components to get notes and add notes using Appwrite dynamically. In `index.js`, update the following to fetch data from the Appwrite database:


```javascript
    import { Client, Graphql } from 'appwrite'
    import HeaderText from '@/components/HeaderText'
    import AddNoteForm from '@/components/AddNoteForm'
    import NotesList from '@/components/NotesList'
    import NoteItem from '@/components/NoteItem'
    const Home = () => {
      const client = new Client()
        .setEndpoint('https://localhost:5000/v1/graphql') // Your Appwrite Endpoint
        .setProject('[REPLACE_PROJECT_ID]')
      const graphql = new Graphql(client)
      // get data from database
      const query = graphql.mutation({
        query: `query GetNotes {
          databasesGetDocument(
            databaseId: "[REPLACE_DATABASE_ID]",
            collectionId: "[REPLACE_COLLECTION_ID]",
            documentId: "[REPLACEDOCUMENT_ID]"
        ) {
            _id
            _collectionId
            _databaseId
            _createdAt
            _updatedAt
            _permissions
            data
        }
        }`,
      })
      query.then((response) => {
        console.log(response)
      })
      // use the result to pass data
    
      return (
        <div className='container'>
          <HeaderText />
          <AddNoteForm />
          {/* use data from query API above */}
          {response.data.databasesGetDocument.data(({ title, notes }) => (
            <NoteItem title={title} notes={notes} />
          ))}
        </div>
      )
    }
    export default Home
    
```


## Creating Notes:

We will update our form to take in user input values:

```javascript
    <form onSubmit={handleSubmit}>
            <div className='mb-3'>
              <label htmlFor='title' className='form-label'>
                Title
              </label>
              <input
                type='text'
                className='form-control'
                placeholder='Note Title'
                value={noteTitle}
                onChange={(event) => setNoteTitle(event.target.value)}
              />
            </div>
            <div className='mb-3'>
              <label htmlFor='note' className='form-label'>
                Text
              </label>
              <textarea
                placeholder='Note Text'
                className='form-control'
                value={noteText}
                onChange={(event) => setNoteText(event.target.value)}
              />
            </div>
            <br />
            <button type='submit' className='btn btn-primary'>
              Add Note
            </button>
          </form>

```

We will then add a mutation to our GraphQL schema to enable data from the form to be sent to Appwrite.


```javascript
    const query = graphql.mutation({
        query: `query AddNotes {
            databasesCreateDocument(
                databaseId: "[REPLACE_DATABASE_ID]",
                collectionId: "[REPLACE_COLLECTION_ID]",
                documentId: "[REPLACEDOCUMENT_ID]",
                title: $title, text: $text
                {
                    id
                    title
                    text
                }
            )
        }`
      })
```

Here's a breakdown of the code:

`graphql.mutation`: This function is likely defined elsewhere and creates a new mutation in the GraphQL API.

`databasesCreateDocument`: This mutation creates a document in Appwrite database collection.

`title: $title` & `text: $text`: These are the values for the title and text fields of the document. They are passed in as variables, denoted by the $ symbol.

`id`, `title`, & `text`: These document fields will be returned after the mutation is executed.

This code creates a GraphQL mutation that creates a document in a database collection with a specified ID, title, and text. The id, title, and text of the created document will be returned.


## Deleting a Note

To delete a note, we will add a delete button to a note card and create a function that will delete a note when a user clicks the delete button.

To create the delete button, update the Note card to:

```jsx

    <div className='card mb-3' key={note.id}>
        <div className='card-header'>{note.title}</div>
        <div className='card-body'>
            <p className='card-text'>{note.text}</p>
        </div>
        <div className='card-footer'>
            <button className='btn btn-danger' onClick={() => deleteNote(note.id)}>
            Delete
            </button>
        </div>
    </div>
```

On the button, we added an event handler, `onClick`, which will fire up the `deleteNote` function:

```javascript
    onClick={() => deleteNote(note.id)}
```

We then create the `deleteNote` GraphQL mutation:


```javascript
     const query = graphql.mutation({
        query: `query DeleteNote {
            databasesDeleteDocument(
                databaseId: "[REPLACE_DATABASE_ID]",
                collectionId: "[REPLACE_COLLECTION_ID]",
                documentId: "[REPLACEDOCUMENT_ID]",
                id: $id
                {
                    id
                    title
                    text
                }
            )
        }`
      })
```

The `deleteNote` function takes an input parameter "id", which is obtained from the note card a user clicks. It then filters out the specific item and the `setNotes` state updates the list of notes.


## Editing a Note

We will add an edit button to the Note card:


```jsx
    <button className='btn btn-warning' onClick={() => editNote(note.id)} >
    Edit
    </button>
```

In the button we will call the `editNote` function:


```javascript
      const editNote = id => {
        setEditingNoteId(id);
        const noteToEdit = notes.find(note => note.id === id);
        setNewTitle(noteToEdit.title);
        setNewText(noteToEdit.text);
      };
```

We will then update the graphQL mutation to send in an edit request:


```javascript
    const query = graphql.mutation({
        query: `query EditNote {
            databasesEditDocument(
                databaseId: "[REPLACE_DATABASE_ID]",
                collectionId: "[REPLACE_COLLECTION_ID]",
                documentId: "[REPLACEDOCUMENT_ID]",
                $id: ID!, $title: String!, $text: String!
                {
                    id
                    title
                    text
                }
            )
        }`
      })
```


## Demo

{% embed https://www.dropbox.com/s/0noxqgfmwgikczk/video_1_AdobeExpress.mp4?dl=0 %}



## Conclusion

In this post, the process of installing, creating, and setting up the Appwrite application and the Next.js version 13 project has been demonstrated, including how Appwrite GraphQL works and how it can be integrated.


## Resources
- [Appwrite Documentation](https://appwrite.io/docs?utm_source=hackmamba&utm_medium=blog&utm_campaign=hackmamba)
[](https://appwrite.io/docs)
- [Appwrite GraphQL](https://appwrite.io/docs/graphql?utm_source=hackmamba&utm_medium=blog&utm_campaign=hackmamba)
[](https://appwrite.io/docs/graphql)
- [Using GraphQL in Next](https://nextjs.org/docs/api-routes/introduction)[.js](https://nextjs.org/docs/api-routes/introduction)
[](https://nextjs.org/docs/api-routes/introduction)