How to Manage Multiple Appwrite Functions in a Single Repository
Tags: serverless, javascript, webdev, tutorial
Published: 2023-10-27 21:34:48

In recent years, serverless computing has revolutionized the developer landscape, gaining widespread adoption for its benefits. Within this serverless paradigm, developers utilize serverless functions to execute tasks while reducing server costs and ensuring the scalability of their applications.

[Appwrite](https://appwrite.io/?utm_source=hackmamba&utm_medium=hackmamba-blog), an open-source backend-as-a-service (BaaS) provider, has embraced this serverless revolution to empower developers further. With Appwrite's robust platform, developers can harness the full potential of serverless functions to create highly responsive and cost-effective web applications. 

This article explores how to develop serverless functions on Appwrite and manage functions in a single GitHub repository. We'll build a Nuxt.js app that showcases how to create, use, and manage serverless functions with Appwrite.

## Prerequisites

To follow along with this article, you’ll need the following:

1. A basic understanding of JavaScript and Nuxt.js
2. [Node.js](https://nodejs.org/en/) installed on your machine and a basic understanding of Node.js
3. An Appwrite Cloud account (create one [here](https://cloud.appwrite.io/))

## Repository

All the code used in this article can be found in this repository:

https://github.com/folucode/quote-todo-app

## Function setup

In this article, we’ll demonstrate building a simple to-do suggestion app: an app that suggests random things to do and also gives us motivational quotes to help us get motivated to complete the task. We’ll create two functions, one to suggest a random task and the other to give us a motivational quote. To achieve this, we’ll use Nuxt.js for the frontend of the app.

### Creating the functions  

First, let’s log in to our Appwrite cloud account and create a new project by clicking **Create project** and naming it `Task-Suggestion`.
****
![Appwrite projects dashboard](https://paper-attachments.dropboxusercontent.com/s_2ED46675DFC7A75178CE3FF2283700A856C8EF4F940219E84088BF51FEDF742A_1696323627815_Screenshot+2023-10-03+at+09.45.29.png)


Next, on the sidebar, click on **Functions** and then **Create function**.

![appwrite dashboard](https://paper-attachments.dropboxusercontent.com/s_2ED46675DFC7A75178CE3FF2283700A856C8EF4F940219E84088BF51FEDF742A_1696323918677_Screenshot+2023-10-03+at+10.04.19.png)


Since we’ll be managing our functions in a GitHub repository, click on the GitHub button, choose GitHub account, and then give it access to all repositories by selecting **All repositories**. Then, click on **Install & Authorize**.

After this, we‘ll be redirected to Appwrite for a dropdown list of our GitHub repositories. For this project, we will be using the Node.js runtime for our function.

Click on **Node.js** in the **Quickstart** section to set up our function and also create a GitHub repository to manage it. Here are the specifics:


- **Configuration:** Name the function **Get Quote** and choose any Node.js runtimes from the dropdown list. Click on **Next**.
- **Variables:** We won't use environment variables in our function, so leave it as it is and click **Next**.
- **Connect:** Select the option to **create a new repository** and click **Next**.
- **Repository:** Give the repository a name, make it private or public, and then click **Next**. Since we connected our GitHub account earlier, this new repository will be created in the GitHub account to which we connected the project.
- **Branch:** Select the **main** branch, type `functions/get_quote` as the root directory of the function, and then click **Create**. Putting each function in its folder inside a central directory named **functions** is standard practice. This facilitates easy management of each function. 

After this, our function is successfully created and deployed. It will also be in a repository on our GitHub profile.

![Appwrite function deployment dashboard](https://paper-attachments.dropboxusercontent.com/s_2ED46675DFC7A75178CE3FF2283700A856C8EF4F940219E84088BF51FEDF742A_1696328335787_Screenshot+2023-10-03+at+10.37.42.png)


Following the same steps, let’s create a new `Get Task` function. In the **Connect** section, select **Add to existing repository**. Next, select the previous repository we created for the `Get Quote` function. In the **Branch** section, type `functions/get_task` as the root directory and then click **Create**.

Appwrite will deploy the new function, and it will appear in the same repository. The GitHub repository should now look like this:

![GitHub functions repository](https://paper-attachments.dropboxusercontent.com/s_2ED46675DFC7A75178CE3FF2283700A856C8EF4F940219E84088BF51FEDF742A_1696328897840_Screenshot+2023-10-03+at+11.25.51.png)


and our Appwrite dashboard should look like this:

![Appwrite functions dashboard](https://paper-attachments.dropboxusercontent.com/s_2ED46675DFC7A75178CE3FF2283700A856C8EF4F940219E84088BF51FEDF742A_1696328983484_Screenshot+2023-10-03+at+11.28.55.png)



### Writing the function logic

Now that we've created our functions, deployed them, and connected them to GitHub, we have to write the logic for our functions.

We first need to clone the project from GitHub using the following command:


    git clone <repo-git-url>

Open the project in a code editor and navigate to **functions > get_quote > src > main.js.** We’ll see some boilerplate code that was put in there by Appwrite. Replace the boilerplate code with the code below:

```javascript
    export default async ({ req, res, log, error }) => {
      try {
        const motivationalQuotes = [
          {
            quote: "Success is not in what you have, but who you are.",
            author: "Bo Bennett"
          },
          {
            quote: "Your time is limited, don't waste it living someone else's life.",
            author: "Steve Jobs"
          },
          {
            quote: "The only person you are destined to become is the person you decide to be.",
            author: "Ralph Waldo Emerson"
          },
          {
            quote: "The best revenge is massive success.",
            author: "Frank Sinatra"
          },
          {
            quote: "Don't be afraid to give up the good to go for the great.",
            author: "John D. Rockefeller"
          }
        ];
      
        const randomIndex = Math.floor(Math.random() * motivationalQuotes.length);
        const randomQuote = motivationalQuotes[randomIndex];
       
        return res.json({
          statusCode: 200,
          body: JSON.stringify({ quote: randomQuote.quote, author: randomQuote.author }),
        });
        
      } catch (error) {
        return res.json({
          statusCode: 200,
          body: JSON.stringify({ error: 'An error occurred while fetching the quote.' }),
        });
      }
    };
 ```  

In this function, we define an array of motivational quotes, each being an object with a **quote** and an **author**. We then select a random **quote** and **author** and return a **JSON** response containing the selected **quote** and **author**. In case of any errors during this process, we return a **JSON** response indicating an error occurred.

Next, navigate to **functions > get_task > src > main.js** and replace the boilerplate code with this:

```javascript
    export default async ({ req, res, log, error }) => {
      try {
        const tasks = [
          "Buy groceries",
          "Go for a run",
          "Read a book",
          "Call a friend",
          "Write a blog post",
          "Clean the house",
          "Cook dinner",
          "Watch a movie",
          "Take a walk in the park",
          "Plan a vacation",
          "Organize your closet",
          "Listen to music",
          "Practice mindfulness",
          "Try a new recipe",
          "Write in my journal",
        ];
    
        const randomTaskIndex = Math.floor(Math.random() * tasks.length);
        const randomTask = tasks[randomTodoIndex];
    
        return res.json({
          statusCode: 200,
          body: JSON.stringify({ task: randomTask }),
        });
      } catch (error) {
        return res.json({
          statusCode: 200,
          body: JSON.stringify({ error: 'An error occurred while fetching task.' }),
        });
      }
    };
```    

In the function above, we define an array of **tasks**, then select a random **task** and return a **JSON** response containing the chosen **task**. In case of any errors during this process, we return a **JSON** response indicating that an error occurred.

After doing this, push the changes to GitHub, and our functions in Appwrite will automatically redeploy with the new changes applied.

## Frontend setup

We're using Nuxt.js for our frontend to implement the functions. To install Node, go to the [Node.js website](https://nodejs.org/en/) and follow the instructions to install the software compatible with our operating system. 

Then, verify the installation using:


    node -v

To create the Nuxt.js app, run the command below; it will automatically set up a boilerplate Nuxt.js app:


    npx nuxi@latest init <project-name>

Next, change the directory to the directory of the app we just created:


    cd <project-name>

Now run `npm run dev` or `yarn dev` to start the development server on `http://localhost:3000`.

## Building the functionality

Open the `app.vue` file and replace the boilerplate code with the code below:

```javascript
    <template>
      <div class="parent">
        <div class="quote">
          <blockquote>{{ quote }}</blockquote>
          <p>- {{ author }} - </p>
        </div>
        <div class="todo">
          <p>- {{ task }} - </p>
        </div>
        <div class="get-quote">
          <button @click="getQuote">Get Quote</button>
        </div>
        <div class="get-todo">
          <button @click="getTask">Get Todo</button>
        </div>
      </div>
    </template>
    
    <style>
    .parent {
      display: grid;
      grid-template-columns: repeat(2, 1fr);
      grid-template-rows: repeat(2, 1fr);
      grid-column-gap: 0px;
      grid-row-gap: 0px;
      justify-content: center;
      align-items: center;
      place-items: center;
      width: 400px;
      margin-top: 150px;
      margin-left: 35%;
    }
    .quote {
      grid-area: 1 / 1 / 2 / 2;
    }
    .todo {
      grid-area: 1 / 2 / 2 / 3;
    }
    .get-quote {
      grid-area: 2 / 1 / 3 / 2;
    }
    .get-todo {
      grid-area: 2 / 2 / 3 / 3;
    }
    .quote {
      width: 250px;
      border-radius: 5px;
      padding: 5px;
      text-align: center;
      background-color: rgb(96, 206, 206);
      margin: 10px;
    }
    .todo {
      width: 250px;
      border-radius: 5px;
      padding: 5px;
      text-align: center;
      background-color: rgb(225, 73, 73);
    }
    blockquote {
      font-weight: bolder;
      font-size: larger;
      color: blanchedalmond;
      font-style: italic;
    }
    p {
      font-size: larger;
    }
    button {
      width: 150px;
      padding: 10px;
      background-color: brown;
      color: white;
      border: 2px solid white;
      border-radius: 5px;
    }
    button:hover {
      cursor: pointer;
    }
    </style>
```
In the code above, we set up the UI for the app, define its positioning, and style it. Now, we need to implement the `getQuote` and `getTask` functions.

After the style tag, add the code below:

```javascript
    <script>
    import { Client, Functions } from 'appwrite';
    
    const client = new Client()
      .setEndpoint('https://cloud.appwrite.io/v1')
      .setProject('[PROJECT-ID]');
    
    const functions = new Functions(client);
    
    export default {
      methods: {
        async getQuote() {
          try {
            const response = await functions.createExecution(
              '[FUNCTION-ID]',
              JSON.stringify({}),
              false,
              '/',
              'GET',
              {}
            );
            const result = JSON.parse(response.responseBody);
            const body = JSON.parse(result.body);
            this.quote = body.quote;
            this.author = body.author;
          } catch (error) {
            console.error('Error fetching the quote:', error);
          }
        },
        async getTask() {
          try {
            const response = await functions.createExecution(
              '[FUNCTION-ID]',
              JSON.stringify({}),
              false,
              '/',
              'GET',
              {}
            );
            const result = JSON.parse(response.responseBody);
            const body = JSON.parse(result.body);
            this.task = body.task;
          } catch (error) {
            console.error('Error fetching the quote:', error);
          }
        },
      },
      data() {
        return {
          quote: '',
          author: '',
          task: '',
        };
      },
    };
    </script>
```
In the code above, we:

1. Import the `appwrite` library to create a client and interact with Appwrite functions.
2. Initialize the Appwrite client with the endpoint and our `project ID`. We get the `project ID` from our Appwrite dashboard by clicking on the **Overview** tab.
3. Define the two methods, `getQuote` and `getTask`, which are used to call specific Appwrite functions.
    - `getQuote` sends a request to the `Get Quote` Appwrite function using its `function ID` and expects a response containing a `quote` and `author`. It then updates the Nuxt component's data properties `quote` and `author` with the retrieved values. We get the `function ID` from our Appwrite dashboard by clicking the **Functions** tab.
    - `getTask` sends a request to the `Get Task` Appwrite function using its `function ID` and expects a response containing a **Task** item. It updates the Nuxt component's `task` data property with the retrieved value. We get the `function ID` from our Appwrite dashboard by clicking the **Functions** tab.
4. Initialize the Nuxt component's data properties with empty values, including **quote**, **author**, and **task**.

When we run our app, it should work like so:

https://www.loom.com/share/27fe40dc23574b198d9e5ad9cbb8716a?sid=cf39da90-9d6d-419e-98d0-7f640c929890

## Conclusion 

In this article, we've learned how to create and manage Appwrite functions all in one place on GitHub. We made two functions that perform specific tasks, helping us understand how to use Appwrite functions in our projects. We also learned that Appwrite deploys our functions automatically whenever we make changes, making our work smooth, and this simplifies the development process and ensures that our applications remain seamlessly up-to-date.

We also saw how we can have our functions in the same repository as our app. This helped to easily manage and sync all changes all in one single repository.

## Resources
- [Nuxt.js Documentation](https://nuxt.com/docs/getting-started/installation)
- [Appwrite Functions Documentation](https://appwrite.io/docs/products/functions?utm_source=hackmamba&utm_medium=hackmamba-blog)