DEV Community

Cover image for How to Create a Note-taking App with Appwrite and GraphQL in Next.js 13
Chris Achinga for Hackmamba

Posted on

How to Create a Note-taking App with Appwrite and GraphQL in Next.js 13

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, GraphQL, and Next.js.

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:

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

    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
Enter fullscreen mode Exit fullscreen mode

Windows Command Prompt (CMD)

    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
Enter fullscreen mode Exit fullscreen mode

Powershell

    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
Enter fullscreen mode Exit fullscreen mode

The command will prompt the following configurations:

    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>
Enter fullscreen mode Exit fullscreen mode

image

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

Creating an Appwrite Project

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

image

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

image

Creating a Database and a Collection

Click on Create database to create a new database.

image

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

image

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

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

image

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:

    cd notes-app
    npm run dev
Enter fullscreen mode Exit fullscreen mode

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:

This is a Next.js project bootstrapped with create-next-app.

Getting Started

First, run the development server:

npm run dev
# or
yarn dev
# or
pnpm dev
Enter fullscreen mode Exit fullscreen mode

Open http://localhost:3000 with your browser to see the result.

You can start editing the page by modifying pages/index.js. The page auto-updates as you edit the file.

API routes can be accessed on http://localhost:3000/api/hello. This endpoint can be edited in pages/api/hello.js.

The pages/api directory is mapped to /api/*. Files in this directory are treated as API routes instead of React pages.

This project uses next/font to automatically optimize and load Inter, a custom Google Font.

Learn More

To learn more about Next.js, take a look at the following resources:

You can check out the Next.js GitHub repository - your feedback and contributions are welcome!

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

    git clone https://github.com/achingachris/Note-Taking-Application-NextJS.git
Enter fullscreen mode Exit fullscreen mode

After cloning, install the node packages by running:

    npm install
Enter fullscreen mode Exit fullscreen mode

To run the application, use the following command:

    npm run dev
Enter fullscreen mode Exit fullscreen mode

The project will run on localhost:3000

image

Breaking down the Next.js Application

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

    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.',
    }
Enter fullscreen mode Exit fullscreen mode

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

    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
Enter fullscreen mode Exit fullscreen mode

Using GraphQL & Appwrite's GraphQL

Appwrite's GraphQL API 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:

    #!/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/
Enter fullscreen mode Exit fullscreen mode

image

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

image

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.

    npm i appwrite
Enter fullscreen mode Exit fullscreen mode

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

    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);
    });

Enter fullscreen mode Exit fullscreen mode

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:
    const client = new Client()
        .setEndpoint('https://localhost:5000/v1/graphql') // Your Appwrite Endpoint
        .setProject('[PROJECT_ID]')
Enter fullscreen mode Exit fullscreen mode

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

image
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:

    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

Enter fullscreen mode Exit fullscreen mode

Creating Notes:

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

    <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>

Enter fullscreen mode Exit fullscreen mode

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

    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
                }
            )
        }`
      })
Enter fullscreen mode Exit fullscreen mode

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:


    <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>
Enter fullscreen mode Exit fullscreen mode

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

    onClick={() => deleteNote(note.id)}
Enter fullscreen mode Exit fullscreen mode

We then create the deleteNote GraphQL mutation:

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

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:

    <button className='btn btn-warning' onClick={() => editNote(note.id)} >
    Edit
    </button>
Enter fullscreen mode Exit fullscreen mode

In the button we will call the editNote function:

      const editNote = id => {
        setEditingNoteId(id);
        const noteToEdit = notes.find(note => note.id === id);
        setNewTitle(noteToEdit.title);
        setNewText(noteToEdit.text);
      };
Enter fullscreen mode Exit fullscreen mode

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

    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
                }
            )
        }`
      })
Enter fullscreen mode Exit fullscreen mode

Demo

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

Top comments (1)

Collapse
 
codercatdev profile image
Alex Patterson

Really great use of the Appwrite GraphQL!!