Going serverless with MongoDB Realm - Vue.js Version
Tags: serverless, mongodb, vue, typescript
Published: 2021-11-23 07:02:52

---
title: Going serverless with MongoDB Realm - Vue.js Version
published: true
description: 
tags: #serverless #mongoDB #Vuejs #typeScript
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/008f1sxvetnryw0js7nn.png
---

Serverless architecture is a pattern of running and building applications and services without having to manage infrastructure. It involves the applications and services running on the server, but all the server management is done by a cloud provider.

This post will discuss building a fullstack user management application using [MongoDB](https://www.mongodb.com/), [MongoDB Realm](https://www.mongodb.com/realm), and [Vue.js](https://vuejs.org/). At the end of this tutorial, we will learn how to create a database on MongoDB, serverless functions as our endpoints using MongoDB Realm and consume the endpoints in a Vue.js application.

MongoDB Realm is a development platform designed for building mobile, web, desktop, and IoT applications. It offers services like data synchronization, serverless functions, triggers, user authentication, e.t.c. We can build and maintain application on MongoDB Realm using any of the following:

- [Realm UI](https://docs.mongodb.com/realm/manage-apps/deploy/manual/deploy-ui/#std-label-deploy-ui):  a browser-based option to create and maintain application
- [Realm CLI](https://docs.mongodb.com/realm/manage-apps/deploy/manual/deploy-cli/#std-label-deploy-cli): a CLI-based option to define and deploy applications
- [GitHub Deploy](https://docs.mongodb.com/realm/manage-apps/deploy/automated/deploy-automatically-with-github/#std-label-deploy-github): use configuration files on Github to deploy applications from a Github repository
- [Admin API](https://docs.mongodb.com/realm/admin/api/v3/#std-label-admin-api): an HTTP-based request to manage your applications.

In this post, we will be using [Realm UI](https://docs.mongodb.com/realm/manage-apps/deploy/manual/deploy-ui/#std-label-deploy-ui) to build our applications.

You can code along by cloning this repository (**main branch**) [here](https://github.com/Mr-Malomz/vue-realm). If you prefer to view the complete code, checkout to the **dev** branch of this same repository.

In this tutorial, we will focus on implementations only. The project UI has already been set up with [TailwindCSS](https://tailwindcss.com/).

You can check out the React.js version [here](https://dev.to/hackmamba/going-serverless-with-mongodb-realm-reactjs-version-jh6).


# Prerequisites

The following steps in this post require JavaScript and Vue.js experience. Experience with TypeScript isn’t a requirement, but it’s nice to have.

We also need a [MongoDB account](https://www.mongodb.com/) to host the database and create serverless functions. [**Signup**](https://www.mongodb.com/cloud/atlas/register) **is completely free**.


# Let’s code
## Running the Project

To get started, we need to navigate to the project location, open our terminal and install project dependency as shown below:


    npm install

With that done, we can start a development server using the command below:

    npm run serve


![](https://paper-attachments.dropbox.com/s_5F12CB220A74A4DEB6FF68681B47C7B21F99639FF61AAE2AFC0BCCDD4BDF4016_1637580003144_Screenshot+2021-11-22+at+12.19.26.png)
![](https://paper-attachments.dropbox.com/s_5F12CB220A74A4DEB6FF68681B47C7B21F99639FF61AAE2AFC0BCCDD4BDF4016_1637580003179_Screenshot+2021-11-22+at+12.19.46.png)



## Setting up MongoDB

To get started, we need to log in or sign up into our [MongoDB](http://) account and follow the option that applies to us:

**For a New Account (Sign Up)**
First, we need to answer a few questions to help MongoDB help set up our account. Then click on **Finish.**

![Setup MongoDB](https://paper-attachments.dropbox.com/s_B58C50BB61437E91E681B5825981F54733906EC9A6070DFB4A21109C66F0E3FA_1637334362262_Screenshot+2021-11-19+at+15.58.45.png)


Select **Shared** as the type of database.

![Shared highlighted in red](https://paper-attachments.dropbox.com/s_B58C50BB61437E91E681B5825981F54733906EC9A6070DFB4A21109C66F0E3FA_1637334670330_Screenshot+2021-11-19+at+15.59.38.png)


Click on **Create** to setup a cluster. This might take sometime to setup.

![Creating a cluster](https://paper-attachments.dropbox.com/s_B58C50BB61437E91E681B5825981F54733906EC9A6070DFB4A21109C66F0E3FA_1637334961608_Screenshot+2021-11-19+at+16.13.28.png)


Next, we need to create a user to access the database externally by inputting the **Username**, **Password** and then click on **Create User**. We also need to add our IP address to safely connect to the database by clicking on the **Add My Current IP Address** button. Then click on **Finish and Close** to save changes.


![Create user](https://paper-attachments.dropbox.com/s_B58C50BB61437E91E681B5825981F54733906EC9A6070DFB4A21109C66F0E3FA_1637336863099_Screenshot+2021-11-19+at+16.29.11.png)
![Add IP](https://paper-attachments.dropbox.com/s_B58C50BB61437E91E681B5825981F54733906EC9A6070DFB4A21109C66F0E3FA_1637336863177_Screenshot+2021-11-19+at+16.31.34.png)


On saving the changes, we should see a Database Deployments screen, as shown below:

![cluster](https://paper-attachments.dropbox.com/s_5F12CB220A74A4DEB6FF68681B47C7B21F99639FF61AAE2AFC0BCCDD4BDF4016_1637582445471_Screenshot+2021-11-22+at+12.33.04.png)


**For an Existing Account (Log In)**
Click the project dropdown menu and click on the **New Project** button.

![New Project](https://paper-attachments.dropbox.com/s_B58C50BB61437E91E681B5825981F54733906EC9A6070DFB4A21109C66F0E3FA_1637365380025_Screenshot+2021-11-20+at+00.33.27.png)


Enter the `realmVue` as the project name, click on **Next** and then click **Create Project**

![enter project name](https://paper-attachments.dropbox.com/s_5F12CB220A74A4DEB6FF68681B47C7B21F99639FF61AAE2AFC0BCCDD4BDF4016_1637582923909_Screenshot+2021-11-22+at+13.07.30.png)
![create project](https://paper-attachments.dropbox.com/s_5F12CB220A74A4DEB6FF68681B47C7B21F99639FF61AAE2AFC0BCCDD4BDF4016_1637582923964_Screenshot+2021-11-22+at+13.07.44.png)


Click on **Build a Database**

![click on Build a Database](https://paper-attachments.dropbox.com/s_5F12CB220A74A4DEB6FF68681B47C7B21F99639FF61AAE2AFC0BCCDD4BDF4016_1637583023976_Screenshot+2021-11-22+at+13.09.56.png)


Select **Shared** as the type of database.

![Shared highlighted in red](https://paper-attachments.dropbox.com/s_B58C50BB61437E91E681B5825981F54733906EC9A6070DFB4A21109C66F0E3FA_1637334670330_Screenshot+2021-11-19+at+15.59.38.png)


Click on **Create** to setup a cluster. This might take sometime to setup.

![Creating a cluster](https://paper-attachments.dropbox.com/s_B58C50BB61437E91E681B5825981F54733906EC9A6070DFB4A21109C66F0E3FA_1637334961608_Screenshot+2021-11-19+at+16.13.28.png)


Next, we need to create a user to access the database externally by inputting the **Username**, **Password** and then clicking on **Create User**. We also need to add our IP address to safely connect to the database by clicking on the **Add My Current IP Address** button. Then click on **Finish and Close** to save changes.

![Create user](https://paper-attachments.dropbox.com/s_B58C50BB61437E91E681B5825981F54733906EC9A6070DFB4A21109C66F0E3FA_1637336863099_Screenshot+2021-11-19+at+16.29.11.png)
![Add IP](https://paper-attachments.dropbox.com/s_B58C50BB61437E91E681B5825981F54733906EC9A6070DFB4A21109C66F0E3FA_1637336863177_Screenshot+2021-11-19+at+16.31.34.png)


On saving the changes, we should see a Database Deployments screen, as shown below:

![cluster](https://paper-attachments.dropbox.com/s_5F12CB220A74A4DEB6FF68681B47C7B21F99639FF61AAE2AFC0BCCDD4BDF4016_1637583424964_Screenshot+2021-11-22+at+13.16.38.png)



## Loading Sample Data

Next, we need to populate our database with users' sample data. To do this, click on the **Browse Collections** button

![browse collection](https://paper-attachments.dropbox.com/s_5F12CB220A74A4DEB6FF68681B47C7B21F99639FF61AAE2AFC0BCCDD4BDF4016_1637583539121_Screenshot+2021-11-22+at+13.16.38.png)


Click on **Add My Own Data**, input `vueRealmDB` and `vueRealmCol` as the database and collection name, and click on **Create**.

![add my own data](https://paper-attachments.dropbox.com/s_5F12CB220A74A4DEB6FF68681B47C7B21F99639FF61AAE2AFC0BCCDD4BDF4016_1637584046943_Screenshot+2021-11-22+at+13.22.36.png)
![create](https://paper-attachments.dropbox.com/s_5F12CB220A74A4DEB6FF68681B47C7B21F99639FF61AAE2AFC0BCCDD4BDF4016_1637584046976_Screenshot+2021-11-22+at+13.25.26.png)


Next, we need to insert these sample data:

```json
{
"name": "daniel mark"
"location": "new york"
"title": "software engineer"
}
{
"name": "clara patrick"
"location": "lisbon"
"title": "data engineer"
}
```

To do this, click on the **Insert Document** button, fill in the details above and click on **Insert** to save.

![insert document](https://paper-attachments.dropbox.com/s_5F12CB220A74A4DEB6FF68681B47C7B21F99639FF61AAE2AFC0BCCDD4BDF4016_1637584413150_Screenshot+2021-11-22+at+13.31.50.png)
![fill and insert](https://paper-attachments.dropbox.com/s_5F12CB220A74A4DEB6FF68681B47C7B21F99639FF61AAE2AFC0BCCDD4BDF4016_1637584413107_Screenshot+2021-11-22+at+13.30.52.png)

![Collection with documents](https://paper-attachments.dropbox.com/s_5F12CB220A74A4DEB6FF68681B47C7B21F99639FF61AAE2AFC0BCCDD4BDF4016_1637584737345_Screenshot+2021-11-22+at+13.38.23.png)

## Creating and configuring MongoDB Realm application

With our database populated, we need to create serverless functions to perform Create, Read, Update and Delete (CRUD) on our database. To do this, select the **Realm** tab, click on **Build your own App**. Then click on **Create Realm Application** to setup our application.

![select app](https://paper-attachments.dropbox.com/s_B58C50BB61437E91E681B5825981F54733906EC9A6070DFB4A21109C66F0E3FA_1637429955105_Screenshot+2021-11-20+at+18.37.09.png)
![create application](https://paper-attachments.dropbox.com/s_B58C50BB61437E91E681B5825981F54733906EC9A6070DFB4A21109C66F0E3FA_1637430101165_Screenshot+2021-11-20+at+18.41.17.png)


 
MongoDB Realm also ships with templates that we can use to build our application quickly. For this tutorial, we will be building from scratch. 

Next, we need to setup permission and rules for our functions. To do this, close the popup guide, click on **Rules**, select the **vueRealmCol** and click on **Configure Collection**. 

![configure collection](https://paper-attachments.dropbox.com/s_5F12CB220A74A4DEB6FF68681B47C7B21F99639FF61AAE2AFC0BCCDD4BDF4016_1637585145195_Screenshot+2021-11-22+at+13.43.52.png)


**MongoDB Realm’s Save and Deploy**
With that done, MongoDB Realm will show us a widget illustrating the concept of Save and Deploy. 

![save and deploy](https://paper-attachments.dropbox.com/s_5F12CB220A74A4DEB6FF68681B47C7B21F99639FF61AAE2AFC0BCCDD4BDF4016_1637585215538_Screenshot+2021-11-22+at+13.46.45.png)


When writing a serverless function, clicking on **Save** creates a development draft that we can test and play around with. At the same time, **Deploy** makes our changes public to be consumed by another application(Vue.js in our case).

Click on **Next** and then **Got it** to continue.

Next, we need to allow **Read** and **Write** permissions for our function and then **Save.**

![read and write permissions](https://paper-attachments.dropbox.com/s_5F12CB220A74A4DEB6FF68681B47C7B21F99639FF61AAE2AFC0BCCDD4BDF4016_1637585456677_Screenshot+2021-11-22+at+13.48.40.png)


Next, navigate to the **Authentication** tab, click on  **Allow users to log in anonymously**, toggle it on and **Save Draft**.

![allow anonymous](https://paper-attachments.dropbox.com/s_B58C50BB61437E91E681B5825981F54733906EC9A6070DFB4A21109C66F0E3FA_1637432705669_Screenshot+2021-11-20+at+19.20.40.png)
![save draft](https://paper-attachments.dropbox.com/s_B58C50BB61437E91E681B5825981F54733906EC9A6070DFB4A21109C66F0E3FA_1637432705712_Screenshot+2021-11-20+at+19.22.47.png)


MongoDB Realm also ships with several authentication options that we can explore. For this tutorial, we will be using the anonymous option. 


## Creating serverless functions on MongoDB Realm

**Get All Users Serverless Function**
With the configuration done, we can now create a serverless function that returns list of users. To do this, navigate to the **Functions** tab, click on **Create New Function**, and input `getAllUsers` as the function name

![create new function](https://paper-attachments.dropbox.com/s_5F12CB220A74A4DEB6FF68681B47C7B21F99639FF61AAE2AFC0BCCDD4BDF4016_1637585888957_Screenshot+2021-11-22+at+13.55.25.png)
![input function name](https://paper-attachments.dropbox.com/s_5F12CB220A74A4DEB6FF68681B47C7B21F99639FF61AAE2AFC0BCCDD4BDF4016_1637585889017_Screenshot+2021-11-22+at+13.55.43.png)


Next, select the **Function Editor** tab and modify the function to the following:

```js
exports = function(arg){
    let collection = context.services.get("mongodb-atlas").db("vueRealmDB").collection("vueRealmCol");

    return collection.find({});
};
```

The snippet above does the following:

- Create a collection variable to access the `vueRealmDB` database and `vueRealmCol` collection
- Return the list of documents in the collection.

Next, we can test our function by clicking on **Run** button to see list of users.

![running getAllUsers function](https://paper-attachments.dropbox.com/s_5F12CB220A74A4DEB6FF68681B47C7B21F99639FF61AAE2AFC0BCCDD4BDF4016_1637586206619_Screenshot+2021-11-22+at+14.02.34.png)


Finally, we need to copy any returned user’s `_id` and save it somewhere; we need it for the next function. Then click on **Save Draft** to create a deployment draft for our function.

![copy id and save draft](https://paper-attachments.dropbox.com/s_5F12CB220A74A4DEB6FF68681B47C7B21F99639FF61AAE2AFC0BCCDD4BDF4016_1637586991637_Screenshot+2021-11-22+at+14.08.47.png)


**Get A User Serverless Function**
To do this, click on the **Functions** tab,  click on **Create New Function**, and input `getSingleUser` as the function name

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ed7ll7y5c5oiwwhcqesr.png)![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d7yfhl4z1r6p1ta7vool.png)


Next, select the **Function Editor** tab, and modify the function to the following:

```js
exports = function(arg){
    let collection = context.services.get("mongodb-atlas").db("vueRealmDB").collection("vueRealmCol");
  
    return collection.findOne({_id: BSON.ObjectId(arg)});
};
```

The snippet above does the following:

- Create a collection variable to access the `vueRealmDB` database and `vueRealmCol` collection
- Return a single user by finding it by its `_id`. Because MongoDB saves documents in BSON, we need to parse the `arg`  as BSON using the `BSON.ObjectId`.

To test our function, Navigate to the **Console** tab, replace the `Hello world!` in the **exports** function with the user’s `_id` we copied earlier and then click on **Run.**

![testing getSingleUser](https://paper-attachments.dropbox.com/s_5F12CB220A74A4DEB6FF68681B47C7B21F99639FF61AAE2AFC0BCCDD4BDF4016_1637588328533_Screenshot+2021-11-22+at+14.26.00.png)


Finally, we need to save our function by clicking on the **Save Draft** button.


**Edit A User Serverless Function**
To do this, we need to follow the same steps as above.

First, click on the **Functions** tab,  click on **Create New Function**, and input `editUser` as the function name.

![editUser](https://paper-attachments.dropbox.com/s_5F12CB220A74A4DEB6FF68681B47C7B21F99639FF61AAE2AFC0BCCDD4BDF4016_1637588507648_Screenshot+2021-11-22+at+14.41.31.png)


Next, select the **Function Editor** tab and modify the function to the following:

```js
exports = function(id, name, location, title){
    let collection = context.services.get("mongodb-atlas").db("vueRealmDB").collection("vueRealmCol");
    let updated = collection.findOneAndUpdate(
        {_id: BSON.ObjectId(id)},
        { $set: { "name": name, "location": location, "title": title } },
        { returnNewDocument: true }
      )
      
    return updated;
};
```

The snippet above does the following:

- Modify the function to accept `id`,  `name`, `location`, and `title` arguments
- Create a collection variable to access the `vueRealmDB` database and `vueRealmCol` collection
- Create an `updated` variable that finds the document by `_id`, update the collection fields, and set a `returnNewDocument` flag to return the updated document.

Next, we can test our function by navigating to the Console tab, replace the `Hello world!` in the **exports** function with required arguments(**_id, name, location, and title**), click on **Run**, and then **Save Draft**.

![editUser](https://paper-attachments.dropbox.com/s_5F12CB220A74A4DEB6FF68681B47C7B21F99639FF61AAE2AFC0BCCDD4BDF4016_1637589196152_Screenshot+2021-11-22+at+14.51.07.png)


**Create A User Serverless Function**
To do this, we need to follow the same steps as before.

First, click on the **Functions** tab,  click on **Create New Function**, and input `createUser` as the function name.

![createUser](https://paper-attachments.dropbox.com/s_5F12CB220A74A4DEB6FF68681B47C7B21F99639FF61AAE2AFC0BCCDD4BDF4016_1637589333325_Screenshot+2021-11-22+at+14.55.16.png)


Next, select the **Function Editor** tab and modify the function to the following:

```js
exports = function(name, location, title){
    let collection = context.services.get("mongodb-atlas").db("vueRealmDB").collection("vueRealmCol");
    
    let newUser = collection.insertOne({"name": name, "location": location, "title": title})

    return newUser;
};
```

The snippet above does the following:

- Modify the function to accept `name`, `location`, and `title` arguments.
- Create a collection variable to access the `vueRealmDB` database and `vueRealmCol` collection.
- Create a new user by inserting the arguments and returning the user.

Next, we can test our function by navigating to the Console tab, replace the `Hello world!` in the **exports** function with required arguments(**name, location, and title**), click on **Run**, and then **Save Draft**.

![createUser](https://paper-attachments.dropbox.com/s_5F12CB220A74A4DEB6FF68681B47C7B21F99639FF61AAE2AFC0BCCDD4BDF4016_1637591396300_Screenshot+2021-11-22+at+14.57.52.png)



**Delete A User Serverless Function**
To do this, we need to follow the same steps as before.

First, click on the **Functions** tab,  click on **Create New Function**, and input `deleteUser` as the function name.

![deleteUser](https://paper-attachments.dropbox.com/s_5F12CB220A74A4DEB6FF68681B47C7B21F99639FF61AAE2AFC0BCCDD4BDF4016_1637591516954_Screenshot+2021-11-22+at+15.31.35.png)


Next, select the **Function Editor** tab and modify the function to the following:

```js
exports = function(id){
    let collection = context.services.get("mongodb-atlas").db("vueRealmDB").collection("vueRealmCol");
    
    let deleteUser = collection.deleteOne({_id: BSON.ObjectId(id)})
    
    return deleteUser;
};
```

The snippet above does the following:

- Modify the function to accept an argument.
- Create a collection variable to access the `vueRealmDB` database and `vueRealmCol` collection.
- Create a `deleteUser` variable for deleting by `_id`.

Next, we can test our function by navigating to the Console tab, replace the `Hello world!` in the **exports** function with required the argument, click on **Run**, and then **Save Draft**.


![deleteUser](https://paper-attachments.dropbox.com/s_5F12CB220A74A4DEB6FF68681B47C7B21F99639FF61AAE2AFC0BCCDD4BDF4016_1637592179074_Screenshot+2021-11-22+at+15.35.21.png)



## Deploying serverless functions

To start using the serverless functions in our application, we need to deploy them. To do this, click on the **Review Draft & Deploy** button, scroll down and then click on **Deploy**.

![review draft & deploy](https://paper-attachments.dropbox.com/s_5F12CB220A74A4DEB6FF68681B47C7B21F99639FF61AAE2AFC0BCCDD4BDF4016_1637592707979_Screenshot+2021-11-22+at+15.41.38.png)
![click on deploy](https://paper-attachments.dropbox.com/s_B58C50BB61437E91E681B5825981F54733906EC9A6070DFB4A21109C66F0E3FA_1637457560813_Screenshot+2021-11-21+at+02.17.08.png)


We should get a prompt showing the status of our deployment.


## Finally! Integration with Vue.js

To integrate MongoDB Realm in our application,  we need to install the dependencies with:

    npm i realm-web

`realm-web` is a [library](https://github.com/realm/realm-js/tree/master/packages/realm-web#readme) for accessing MongoDB Realm from a web-browser.

**Setup an Environment Variable**
First, we need to create a `.env` file in the project root directory, and in this file, add the snippet below:

    VUE_APP_REALM_APP_ID=<your-realm-app-id>

To get our **Realm App ID**, we need to click on the copy icon as shown below:

![copy realm app id by clicking on the highlighted copy icon](https://paper-attachments.dropbox.com/s_5F12CB220A74A4DEB6FF68681B47C7B21F99639FF61AAE2AFC0BCCDD4BDF4016_1637593055750_Screenshot+2021-11-22+at+15.56.30.png)


**Setup MongoDB Realm**
Next, we need to create a `utils` folder in the `src` folder, and in this folder, create a `mongo.client.ts` file and add the code snippet below:

```js
import * as Realm from 'realm-web';

const REALM_APP_ID = process.env.VUE_APP_REALM_APP_ID;
export const app: Realm.App = new Realm.App({ id: REALM_APP_ID! });
export const credentials = Realm.Credentials.anonymous();
```

The snippet above does the following:

- Import the required dependencies.
- Create a variable to store the **Realm App ID**.
- Create and export an instance of MongoDB Realm and pass the App ID. The bang`!` in front of `REALM_APP_ID` tells the compiler to relax the non-null constraint error(Meaning the parameter cannot be null or undefined)
- Create and export the credential type we will be using for this app. We configure this authentication option earlier.


**Get All Users**
To get all users, we need to create an interface to describe the response properties. To do this, we need to create a `models` folder in the `src` folder, and in this folder, create a `user.interface.ts` file and add the code snippet below:

```js
export interface IUser {
    _id? : string;
    name: string;
    location: string;
    title: string
}
```

**PS**: *The question mark in front of* ***_id***  *tells TypeScript that this property is optional since MongoDB automatically generates it.*

Next, we need to modify `App.vue` by updating it with the snippet below:

```vue
<template>
  <div class="">
    <header
      class="h-16 w-full bg-indigo-200 px-6 flex justify-between items-center"
    >
      <h1 class="text-xl text-indigo-900">Vue-Realm</h1>
      <button
        class="text-lg text-white capitalize px-6 py-2 bg-indigo-900 rounded-md"
        @click="handleModal(true)"
      >
        create
      </button>
    </header>
    <section className="mt-10 flex justify-center px-6">
      <ul className="w-full">
        <li
          v-for="user in users"
          :key="user._id"
          className="border-2 p-6 mb-3 rounded-lg flex items-center"
        >
          <section
            className="h-10 w-10 bg-indigo-100 rounded-md flex justify-center items-center mr-4"
          >
            <UserIcon />
          </section>
          <section className="">
            <h2 className="capitalize font-semibold mb-1">{{ user.name }}</h2>
            <p className="capitalize text-gray-500 mb-1">{{ user.location }}</p>
            <p className="capitalize text-indigo-500 font-medium text-sm mb-2">
              {{ user.title }}
            </p>
            <div className="flex">
              <button
                className="text-sm text-red-500 capitalize px-4 py-2 mr-4 border border-red-500 rounded-md"
              >
                delete
              </button>
              <button
                className="text-sm text-white capitalize px-4 py-2 bg-indigo-900 rounded-md"
                @click="handleEditClick()"
              >
                edit
              </button>
            </div>
          </section>
        </li>
      </ul>
    </section>
    <Modal :isModal="isModal" :isEdit="isEdit" :handleModal="handleModal" />
  </div>
</template>

<script lang="ts">
//import goes here
import { IUser } from '@/models/user.interface';
import { app, credentials } from '@/utils/mongo.client';
export default defineComponent({
  name: 'App',
  components: {
    UserIcon,
    Modal,
  },
  data: () => ({
    isModal: false,
    isEdit: false,
    users: [] as IUser[], //add
  }),
  methods: {
    //other functions goes here
    
    //add
    async getListOfUsers() {
      const user: Realm.User = await app.logIn(credentials);
      const listOfUser: Promise<IUser[]> = user.functions.getAllUsers();
      listOfUser.then((resp) => {
        this.users = resp;
      });
    },
  },
  //add
  mounted() {
    this.getListOfUsers()
  },
});
</script>

<style></style>
```

The snippet above does the following:

- Import the `IUser` interface, `app` and `credentials`.
- Create `users`  property to manage the list of users.
- Create a `getListOfUsers`  function to authenticate our application using the `credentials` imported and get the list of users by accessing the `getAllUsers` serverless function we created earlier. Then update the `users` property and use the `mounted` hook to call the function.
    **PS**: *The serverless function (****getAllUsers*** *in our case) called must be the same as the one defined on MongoDB Realm.*
- Update the mark-up to display the list of users.

**Complete App.vue**

```vue
<template>
  <div class="">
    <header
      class="h-16 w-full bg-indigo-200 px-6 flex justify-between items-center"
    >
      <h1 class="text-xl text-indigo-900">Vue-Realm</h1>
      <button
        class="text-lg text-white capitalize px-6 py-2 bg-indigo-900 rounded-md"
        @click="handleModal(true)"
      >
        create
      </button>
    </header>
    <section className="mt-10 flex justify-center px-6">
      <ul className="w-full">
        <li
          v-for="user in users"
          :key="user._id"
          className="border-2 p-6 mb-3 rounded-lg flex items-center"
        >
          <section
            className="h-10 w-10 bg-indigo-100 rounded-md flex justify-center items-center mr-4"
          >
            <UserIcon />
          </section>
          <section className="">
            <h2 className="capitalize font-semibold mb-1">{{ user.name }}</h2>
            <p className="capitalize text-gray-500 mb-1">{{ user.location }}</p>
            <p className="capitalize text-indigo-500 font-medium text-sm mb-2">
              {{ user.title }}
            </p>
            <div className="flex">
              <button
                className="text-sm text-red-500 capitalize px-4 py-2 mr-4 border border-red-500 rounded-md"
              >
                delete
              </button>
              <button
                className="text-sm text-white capitalize px-4 py-2 bg-indigo-900 rounded-md"
                @click="handleEditClick()"
              >
                edit
              </button>
            </div>
          </section>
        </li>
      </ul>
    </section>
    <Modal :isModal="isModal" :isEdit="isEdit" :handleModal="handleModal" />
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import UserIcon from '@/assets/svg/UserIcon.vue';
import Modal from '@/components/Modal.vue';
import { IUser } from '@/models/user.interface';
import { app, credentials } from '@/utils/mongo.client';
export default defineComponent({
  name: 'App',
  components: {
    UserIcon,
    Modal,
  },
  data: () => ({
    isModal: false,
    isEdit: false,
    users: [] as IUser[],
  }),
  methods: {
    handleModal(state: boolean) {
      this.isModal = state;
      this.isEdit = false;
    },
    handleEditClick() {
      this.isModal = true;
      this.isEdit = true;
    },
    async getListOfUsers() {
      const user: Realm.User = await app.logIn(credentials);
      const listOfUser: Promise<IUser[]> = user.functions.getAllUsers();
      listOfUser.then((resp) => {
        this.users = resp;
      });
    },
  },
  mounted() {
    this.getListOfUsers()
  },
});
</script>

<style></style>
```


**Create A User**
To create a user, we must first modify `App.vue` by updating it with the snippet below

```vue
<template>
  <div class="">
    <header
      class="h-16 w-full bg-indigo-200 px-6 flex justify-between items-center"
    >
      <!-- Header content goes here -->
    </header>
    <section className="mt-10 flex justify-center px-6">
      <!-- Section content goes here -->
    </section>
    
    <!-- Modify Modal component -->
    <Modal
      :isModal="isModal"
      :isEdit="isEdit"
      :handleModal="handleModal"
      :updateUserValue="updateUserValue" 
    />
  </div>
</template>

<script lang="ts">
//import goes here
export default defineComponent({
  name: 'App',
  components: {
    UserIcon,
    Modal,
  },
  data: () => ({
    isModal: false,
    isEdit: false,
    users: [] as IUser[],
    userValue: '', //add
  }),
  methods: {
    handleModal(state: boolean) {
      //codes here
    },
    handleEditClick() {
      //codes here
    },
    async getListOfUsers() {
      //codes here
    },
    //add 
    updateUserValue(value: any) {
      this.userValue = value;
    },
  },
  //add
  watch: {
    userValue(latestValue) {
      if (latestValue !== '') {
        this.getListOfUsers();
      }
    },
  },
  mounted() {
    this.getListOfUsers();
  },
});
</script>

<style></style>
```

The snippet above does the following:

- Add a `userValue` property to the `data` property.
- Create a `updateUserValue` function to update the `userValue` property
- Include `watch` component property to monitor the `userValue` property and get the updated list of users if there is a change made to it.
- Update the `Modal` component to accept the `updateUserValue` as a `prop`.

Next, navigate to the `Modal.vue` file inside the `components` folder, update the `props`, and create a user.

```vue
<template>
  <div
    class="h-screen w-screen bg-indigo-900 bg-opacity-30 z-30 top-0 fixed transform scale-105 transition-all ease-in-out duration-100"
    :class="isModal ? 'block' : 'hidden'"
  >
    <!-- Modal content goes here -->
  </div>
</template>

<script lang="ts">
//other import goes here
import { defineComponent, PropType } from 'vue'; //modify
import { IUser } from '@/models/user.interface'; //add
import { app, credentials } from '@/utils/mongo.client'; //add
export default defineComponent({
  name: 'Modal',
  components: { CloseIcon },
  props: {
    isModal: Boolean,
    isEdit: Boolean,
    handleModal: Function,
    updateUserValue: Function as PropType<(value: any) => void>, //add the function to update userValue
  },
  data: () => ({
    name: '',
    location: '',
    title: '',
  }),
  methods: {
    //codes here
    },
    //modify
    async onSubmitForm() {
      const user: Realm.User = await app.logIn(credentials);
      const create = user.functions.createUser(
        this.name,
        this.location,
        this.title
      );
      create.then((resp) => {
        this.updateUserValue!(resp.insertedId);
        this.name = '';
        this.location = '';
        this.title = '';
      });
    },
  },
});
</script>
```

The snippet above does the following:

- Import the required dependencies.
- Add `updateUserValue` to `props` property
- Modify the `onSubmitForm` function to authenticate our application using the `credentials` imported. Create a user by accessing the `createUser` serverless function we created earlier, passing the required arguments (**name**, **location** and **title**)and then updating the `userValue` and form state.


**Edit A User**
To edit a user, we must first modify `App.vue` by creating a property to manage the `_id` of the user we want to edit and function to update it. We also updated the `handleEditClick` function to update the property and pass it as props to the `Modal` component.

```vue
<template>
  <div class="">
    <header
      class="h-16 w-full bg-indigo-200 px-6 flex justify-between items-center"
    >
      <!-- Header content goes here -->
    </header>
    <section className="mt-10 flex justify-center px-6">
      <!-- Section content goes here -->
    </section>
    
    <!-- Modify Modal component -->
    <Modal
      :isModal="isModal"
      :isEdit="isEdit"
      :handleModal="handleModal"
      :updateUserValue="updateUserValue"
      :editingId="editingId"
    />
  </div>
</template>

<script lang="ts">
//import goes here
export default defineComponent({
  name: 'App',
  components: {
    UserIcon,
    Modal,
  },
  data: () => ({
    isModal: false,
    isEdit: false,
    users: [] as IUser[],
    userValue: '',
    editingId: '', //add
  }),
  methods: {
    handleModal(state: boolean) {
      this.isModal = state;
      this.isEdit = false;
    },
    //modify
    handleEditClick(id: string) {
      this.isModal = true;
      this.isEdit = true;
      this.editingId = id;
    },
    async getListOfUsers() {
      //codes here
    },
    updateUserValue(value: any) {
      this.userValue = value;
    },
  },
  watch: {
    //codes here
  },
  mounted() {
    this.getListOfUsers();
  },
});
</script>

<style></style>
```

Next, we need to populate our form when the **Edit** button is clicked. To do this, open `Modal.vue` and update as shown below:

```vue
<template>
  <div
    class="h-screen w-screen bg-indigo-900 bg-opacity-30 z-30 top-0 fixed transform scale-105 transition-all ease-in-out duration-100"
    :class="isModal ? 'block' : 'hidden'"
  >
    <!-- Modal content goes here -->
  </div>
</template>

<script lang="ts">
//import goes here
import { BSON } from 'realm-web'; //add
export default defineComponent({
  name: 'Modal',
  components: { CloseIcon },
  props: {
    //other props goes here
    editingId: String, //add
  },
  data: () => ({
    name: '',
    location: '',
    title: '',
  }),
  methods: {
    onClose(e: Event) {
      //codes here
    },
    async onSubmitForm() {
      //codes here
    },
    //add
    async getAUser() {
      const user: Realm.User = await app.logIn(credentials);
      const getUser: Promise<IUser> = user.functions.getSingleUser(
        new BSON.ObjectID(this.editingId).toString()
      );
      getUser.then((resp) => {
        this.name = resp.name;
        this.location = resp.location;
        this.title = resp.title;
      });
    },
  },
  watch: {
    isEdit(latestValue) {
      if (latestValue == true) {
        this.getAUser();
      } else {
        this.name = '';
        this.location = '';
        this.title = '';
      }
    },
  },
});
</script>
```

The snippet above does the following:

- Import the required dependencies.
- Add `editingId` to `props` property
- Create a `getAUser` function to authenticate our application using the `credentials` imported. Get the selected user details using the `getSingleUser`  serverless function and then update the form values. The `getSingleUser` function also required us to convert `editingId` to string using `BSON.ObjectID` function.
- Include `watch` component property to monitor the `isEdit` state, conditionally call the `getAUser` function and update form state.

Next, we need to update the `onSubmitForm` function to include updating the user’s details by conditionally checking if it is an update action or not. Next, we need to call the `editUser` serverless function and pass in the required parameters. Finally, update the `updateUserValue`, restore the form back to default and close the `Modal` component.

```vue
<template>
  <div
    class="h-screen w-screen bg-indigo-900 bg-opacity-30 z-30 top-0 fixed transform scale-105 transition-all ease-in-out duration-100"
    :class="isModal ? 'block' : 'hidden'"
  >
    <!-- Modal content goes here -->
  </div>
</template>

<script lang="ts">
//import goes here
import { BSON } from 'realm-web'; //add
export default defineComponent({
  name: 'Modal',
  components: { CloseIcon },
  
  props: {
    //other props goes here
  },
  
  data: () => ({
    //codes here
  }),
  
  methods: {
    //codes here
    
    //modify
    async onSubmitForm() {
      const user: Realm.User = await app.logIn(credentials);
      if (this.isEdit) {
        const edit: Promise<IUser> = user.functions.editUser(
          new BSON.ObjectID(this.editingId).toString(),
          this.name,
          this.location,
          this.title
        );
        edit.then((resp) => {
          this.updateUserValue!(resp._id!);
          this.name = '';
          this.location = '';
          this.title = '';
          this.handleModal!(false);
        });
      } else {
        const create = user.functions.createUser(
          this.name,
          this.location,
          this.title
        );
        create.then((resp) => {
          this.updateUserValue!(resp.insertedId);
          this.name = '';
          this.location = '';
          this.title = '';
        });
      }
    },
    
    //codes here
  },
  
  watch: {
    //codes here
  },
});
</script>
```

**Complete Modal.Vue**

```vue
<template>
  <div
    class="h-screen w-screen bg-indigo-900 bg-opacity-30 z-30 top-0 fixed transform scale-105 transition-all ease-in-out duration-100"
    :class="isModal ? 'block' : 'hidden'"
  >
    <div
      class="flex flex-col justify-center items-center h-full w-full open-nav"
      @click="onClose"
    >
      <div class="flex justify-end w-11/12 lg:w-1/2 2xl:w-6/12">
        <div
          role="button"
          class="cursor-pointer w-6 h-6 rounded-full flex items-center justify-center bg-white"
          @click="handleModal()"
        >
          <CloseIcon />
        </div>
      </div>
      <section
        class="w-11/12 lg:w-1/2 2xl:w-6/12 bg-white flex justify-center items-center mt-5 rounded-lg"
      >
        <div class="w-11/12 py-8">
          <h2 class="capitalize text-xl text-gray-500 font-medium mb-4">
            {{ isEdit ? 'Edit User' : 'add user' }}
          </h2>
          <form @submit.prevent="onSubmitForm">
            <fieldset class="mb-4">
              <label class="block text-sm text-gray-500 capitalize mb-1"
                >name</label
              >
              <input
                type="text"
                name="name"
                v-model="name"
                required
                class="w-full h-10 border border-gray-500 rounded-sm px-4"
              />
            </fieldset>
            <fieldset class="mb-4">
              <label class="block text-sm text-gray-500 capitalize mb-1"
                >location</label
              >
              <input
                type="text"
                name="location"
                v-model="location"
                required
                class="w-full h-10 border border-gray-500 rounded-sm px-4"
              />
            </fieldset>
            <fieldset class="mb-4">
              <label class="block text-sm text-gray-500 capitalize mb-1"
                >title</label
              >
              <input
                type="text"
                name="title"
                v-model="title"
                required
                class="w-full h-10 border border-gray-500 rounded-sm px-4"
              />
            </fieldset>
            <button
              class="text-white capitalize px-6 py-2 bg-indigo-900 rounded-md w-full"
            >
              save
            </button>
          </form>
        </div>
      </section>
    </div>
  </div>
</template>

<script lang="ts">
import { defineComponent, PropType } from 'vue';
import CloseIcon from '@/assets/svg/CloseIcon.vue';
import { IUser } from '@/models/user.interface';
import { app, credentials } from '@/utils/mongo.client';
import { BSON } from 'realm-web';
export default defineComponent({
  name: 'Modal',
  components: { CloseIcon },
  props: {
    isModal: Boolean,
    isEdit: Boolean,
    handleModal: Function,
    updateUserValue: Function as PropType<(value: any) => void>,
    editingId: String,
  },
  data: () => ({
    name: '',
    location: '',
    title: '',
  }),
  methods: {
    onClose(e: Event) {
      const target = e.target as HTMLDivElement;
      if (target.classList.contains('open-nav')) {
        this.handleModal!(false);
      }
    },
    async onSubmitForm() {
      const user: Realm.User = await app.logIn(credentials);
      if (this.isEdit) {
        const edit: Promise<IUser> = user.functions.editUser(
          new BSON.ObjectID(this.editingId).toString(),
          this.name,
          this.location,
          this.title
        );
        edit.then((resp) => {
          this.updateUserValue!(resp._id!);
          this.name = '';
          this.location = '';
          this.title = '';
          this.handleModal!(false);
        });
      } else {
        const create = user.functions.createUser(
          this.name,
          this.location,
          this.title
        );
        create.then((resp) => {
          this.updateUserValue!(resp.insertedId);
          this.name = '';
          this.location = '';
          this.title = '';
        });
      }
    },
    async getAUser() {
      const user: Realm.User = await app.logIn(credentials);
      const getUser: Promise<IUser> = user.functions.getSingleUser(
        new BSON.ObjectID(this.editingId).toString()
      );
      getUser.then((resp) => {
        this.name = resp.name;
        this.location = resp.location;
        this.title = resp.title;
      });
    },
  },
  watch: {
    isEdit(latestValue) {
      if (latestValue === true) {
        this.getAUser();
      } else {
        this.name = '';
        this.location = '';
        this.title = '';
      }
    },
  },
});
</script>
```


**Delete A User**
To delete a user, we need to modify `App.vue` by creating a `handleDelete` function as shown below:

```vue
<template>
  <div class="">
    <header
      class="h-16 w-full bg-indigo-200 px-6 flex justify-between items-center"
    >
     <!-- Header content goes here -->
    </header>
    <section className="mt-10 flex justify-center px-6">
      <ul className="w-full">
        <li
          v-for="user in users"
          :key="user._id"
          className="border-2 p-6 mb-3 rounded-lg flex items-center"
        >
          <section
            className="h-10 w-10 bg-indigo-100 rounded-md flex justify-center items-center mr-4"
          >
            <UserIcon />
          </section>
          <section className="">
            <h2 className="capitalize font-semibold mb-1">{{ user.name }}</h2>
            <p className="capitalize text-gray-500 mb-1">{{ user.location }}</p>
            <p className="capitalize text-indigo-500 font-medium text-sm mb-2">
              {{ user.title }}
            </p>
            <div className="flex">
            
            <!-- Modify delete button -->
              <button
                className="text-sm text-red-500 capitalize px-4 py-2 mr-4 border border-red-500 rounded-md"
                @click="deleteAUser(user._id)"
              >
                delete
              </button>
              <button
                className="text-sm text-white capitalize px-4 py-2 bg-indigo-900 rounded-md"
                @click="handleEditClick(user._id)"
              >
                edit
              </button>
            </div>
          </section>
        </li>
      </ul>
    </section>
     <!-- Modal component goes here -->
  </div>
</template>

<script lang="ts">
//import goes here
import { BSON } from 'realm-web'; //add
export default defineComponent({
  name: 'App',
  components: {
    UserIcon,
    Modal,
  },
  data: () => ({
    //codes here
  }),
  methods: {
    handleModal(state: boolean) {
      //codes here
    },
    handleEditClick(id: string) {
      //codes here
    },
    async getListOfUsers() {
     //codes here
    },
    updateUserValue(value: any) {
      //codes here
    },
    //add
    async deleteAUser(id: string) {
      const user: Realm.User = await app.logIn(credentials);
      const delUser = user.functions.deleteUser(
        new BSON.ObjectID(id).toString()
      );
      delUser.then((resp) => {
        this.updateUserValue(resp.deletedCount);
      });
    },
  },
  watch: {
    //codes here
  },
  mounted() {
    //codes here
  },
});
</script>

<style></style>
```


The snippet above does the following:

- Import the required dependencies.
- Creates a `deleteAUser` function that takes an `id` as an argument, authenticate our application using the `credentials`. Delete selected user using the `deleteUser` serverless function and update the `userValue` state.


**Complete App.vue**

```vue
<template>
  <div class="">
    <header
      class="h-16 w-full bg-indigo-200 px-6 flex justify-between items-center"
    >
      <h1 class="text-xl text-indigo-900">Vue-Realm</h1>
      <button
        class="text-lg text-white capitalize px-6 py-2 bg-indigo-900 rounded-md"
        @click="handleModal(true)"
      >
        create
      </button>
    </header>
    <section className="mt-10 flex justify-center px-6">
      <ul className="w-full">
        <li
          v-for="user in users"
          :key="user._id"
          className="border-2 p-6 mb-3 rounded-lg flex items-center"
        >
          <section
            className="h-10 w-10 bg-indigo-100 rounded-md flex justify-center items-center mr-4"
          >
            <UserIcon />
          </section>
          <section className="">
            <h2 className="capitalize font-semibold mb-1">{{ user.name }}</h2>
            <p className="capitalize text-gray-500 mb-1">{{ user.location }}</p>
            <p className="capitalize text-indigo-500 font-medium text-sm mb-2">
              {{ user.title }}
            </p>
            <div className="flex">
              <button
                className="text-sm text-red-500 capitalize px-4 py-2 mr-4 border border-red-500 rounded-md"
                @click="deleteAUser(user._id)"
              >
                delete
              </button>
              <button
                className="text-sm text-white capitalize px-4 py-2 bg-indigo-900 rounded-md"
                @click="handleEditClick(user._id)"
              >
                edit
              </button>
            </div>
          </section>
        </li>
      </ul>
    </section>
    <Modal
      :isModal="isModal"
      :isEdit="isEdit"
      :handleModal="handleModal"
      :updateUserValue="updateUserValue"
      :editingId="editingId"
    />
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import UserIcon from '@/assets/svg/UserIcon.vue';
import Modal from '@/components/Modal.vue';
import { IUser } from '@/models/user.interface';
import { app, credentials } from '@/utils/mongo.client';
import { BSON } from 'realm-web';
export default defineComponent({
  name: 'App',
  components: {
    UserIcon,
    Modal,
  },
  data: () => ({
    isModal: false,
    isEdit: false,
    users: [] as IUser[],
    userValue: '',
    editingId: '',
  }),
  methods: {
    handleModal(state: boolean) {
      this.isModal = state;
      this.isEdit = false;
    },
    handleEditClick(id: string) {
      this.isModal = true;
      this.isEdit = true;
      this.editingId = id;
    },
    async getListOfUsers() {
      const user: Realm.User = await app.logIn(credentials);
      const listOfUser: Promise<IUser[]> = user.functions.getAllUsers();
      listOfUser.then((resp) => {
        this.users = resp;
      });
    },
    updateUserValue(value: any) {
      this.userValue = value;
    },
    async deleteAUser(id: string) {
      const user: Realm.User = await app.logIn(credentials);
      const delUser = user.functions.deleteUser(
        new BSON.ObjectID(id).toString()
      );
      delUser.then((resp) => {
        this.updateUserValue(resp.deletedCount);
      });
    },
  },
  watch: {
    userValue(latestValue) {
      if (latestValue !== '') {
        this.getListOfUsers();
      }
    },
  },
  mounted() {
    this.getListOfUsers();
  },
});
</script>

<style></style>
```

Finally, we can test our application by starting the development server and performing CRUD operations.

![working application](https://paper-attachments.dropbox.com/s_5F12CB220A74A4DEB6FF68681B47C7B21F99639FF61AAE2AFC0BCCDD4BDF4016_1637622880463_Screenshot+2021-11-23+at+00.14.29.png)



# Conclusion

This post discussed how to create a database on MongoDB, create and deploy serverless functions using MongoDB Realm and consume the endpoints in a Vue.js application.

You may find these resources helpful:

- [MongoDB Realm](https://docs.mongodb.com/realm/).
- [TailwindCSS](https://tailwindcss.com/).
- [Realm-Web SDK](https://github.com/realm/realm-js).
- [Serverless computing](https://en.wikipedia.org/wiki/Serverless_computing).
- [BSON](https://www.mongodb.com/json-and-bson)