# Creating a Middleware and Updating a Contact | Full-Stack Google Contacts Clone with AdonisJS (Node.js) and Quasar Framework (Vue.js)

**Author:** Ndianabasi Udonkang  
**Published:** 2021-10-18

In this lesson, we created a middleware for DRYing request lifecycle, improved the validation to support contact update, and updating a contact.

---

## Tags

- [Nodejs](/llms/technical-blog/tag/nodejs.md)
- [Vuejs](/llms/technical-blog/tag/vuejs.md)
- [API Development](/llms/technical-blog/tag/api-development.md)
- [Adonisjs](/llms/technical-blog/tag/adonisjs.md)
- [Quasar Framework](/llms/technical-blog/tag/quasar-framework.md)

## Part of Series: [Full-Stack Google Contacts Clone with Node.js (Adonisjs Framework) and Vue.js (Quasar Framework)](/llms/technical-blog/series/clnwu9bc991hiu3wo2vwmw45/full-stack-google-contacts-clone-with-node-js-adonisjs-framework-and-vue-js-quasar-framework.md)

This article is part of the **[Full-Stack Google Contacts Clone with Node.js (Adonisjs Framework) and Vue.js (Quasar Framework)](/llms/technical-blog/series/clnwu9bc991hiu3wo2vwmw45/full-stack-google-contacts-clone-with-node-js-adonisjs-framework-and-vue-js-quasar-framework.md)** series.

### Articles in this Series:

- [Introduction to Full-Stack Google Contacts Clone with Node.js (Adonisjs Framework) and Vuejs (Quasar Framework)](/llms/technical-blog/article/xe5mlxg43s9rpx1pxsvfdp3r/introduction-to-full-stack-google-contacts-clone-with-node-js-adonisjs-framework-and-vuejs-quasar-framework.md)
- [Workspace Setup | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/fo8str8yjpkz5dygxg875bpw/workspace-setup-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [Frontend Overview | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/nxgmng6fhf1cwjk30coflro2/frontend-overview-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [The Left Drawer | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/m6fagvy2il5h65llxxbbl9os/the-left-drawer-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [Improve The Header | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/jjwbxcg450jmkkcrrmkmwvwj/improve-the-header-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [New Contact Form Design | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/ebguwpkntk3empakunrki4dq/new-contact-form-design-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [Validating the Contact Form with Vuelidate | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/z0xr9m2ljler2cwnpsw2ycwa/validating-the-contact-form-with-vuelidate-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [Designing the Contacts Table | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/h2p1x1z406ib38zu2dci3jur/designing-the-contacts-table-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [Designing the Contacts Table (Part 2) | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/j0iscua9gg8ekuz8ifh6chpn/designing-the-contacts-table-part-2-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [Refactoring the Main Layout | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/uktmlqsivwtr3cvnpld59k9q/refactoring-the-main-layout-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [Improving User Experience with the Contacts Table | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/dzs812auf61ej7qu2cg726dh/improving-user-experience-with-the-contacts-table-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [Designing the Contact Details Page | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/kf9pz97n63fvgfrcy5viwzrg/designing-the-contact-details-page-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [Creating the Contact Edit Page | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/fmr90prj84c9zn0633jc368g/creating-the-contact-edit-page-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [How Software Backends Work | Full-Stack Google Contacts Clone with AdonisJs (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/aca8fcrghz70nn1wqg3uzbum/how-software-backends-work-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-framework-vue-js.md)
- [Setting Up The Backend | Full-Stack Google Contacts Clone with AdonisJs (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/fxb49fmz9ljbwrimbnnzudfv/setting-up-the-backend-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-framework-vue-js.md)
- [Why Choose the AdonisJs Framework? | Full-Stack Google Contacts Clone with AdonisJs (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/lnhm5oudx34yo2869gmcms37/why-choose-the-adonis-js-framework-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-framework-vue-js.md)
- [Setting Up Our API Server with AdonisJs Framework | Full-Stack Google Contacts Clone with AdonisJs (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/x1jgmet84aqj9qggu5mulkh0/setting-up-our-api-server-with-adonis-js-framework-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-framework-vue-js.md)
- [Setting Up Postman with the API Server | Full-Stack Google Contacts Clone with AdonisJS (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/v4qehksislosmuy92qgjr4ct/setting-up-postman-with-the-api-server-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-framework-vue-js.md)
- [The Model-View-Controller Design Pattern in AdonisJS | Full-Stack Google Contacts Clone with AdonisJS (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/h5wqql65iejop5xrplujw458/the-model-view-controller-design-pattern-in-adonis-js-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-framework-vue-js.md)
- [Create Column Definitions & Insert New Contacts | Full-Stack Google Contacts Clone with AdonisJS (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/asc2emsho4u73r6jb2gxjddw/create-column-definitions-and-insert-new-contacts-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-framework-vue-js.md)
- [Data Validation & Sanitisation with AdonisJS | Full-Stack Google Contacts Clone with AdonisJS (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/bcey0ac7m5sbs9hqy1h824sl/data-validation-and-sanitisation-with-adonis-js-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-framework-vue-js.md)
- **Creating a Middleware and Updating a Contact | Full-Stack Google Contacts Clone with AdonisJS (Node.js) and Quasar Framework (Vue.js)** (Current Article)
- [Fetching and Deleting a Contact with AdonisJS | Full-Stack Google Contacts Clone with AdonisJS Framework (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/p6bh0ponq43u3vi6o8uww84x/fetching-and-deleting-a-contact-with-adonis-js-full-stack-google-contacts-clone-with-adonis-js-framework-node-js-and-quasar-framework-vue-js.md)
- [Using Model Factories and Seeders in AdonisJS | Full-Stack Google Contacts Clone with AdonisJS Framework (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/cfotveuxbgjtdp12l6pzcb2y/using-model-factories-and-seeders-in-adonis-js-full-stack-google-contacts-clone-with-adonis-js-framework-node-js-and-quasar-framework-vue-js.md)
- [Creating and Registering a Vuex Module | Full-Stack Google Contacts Clone with AdonisJS Framework (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/cw96ewnzujgsz2e2garhbuzb/creating-and-registering-a-vuex-module-full-stack-google-contacts-clone-with-adonis-js-framework-node-js-and-quasar-framework-vue-js.md)
- [Connecting UI Components to the Vuex Store | Full-Stack Google Contacts Clone with AdonisJS Framework (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/fdyqp17yehbnqrjvjvab4b5b/connecting-ui-components-to-the-vuex-store-full-stack-google-contacts-clone-with-adonis-js-framework-node-js-and-quasar-framework-vue-js.md)
- [Connecting the Frontend to the API Server | Full-Stack Google Contacts Clone with AdonisJS Framework (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/fk4262359gg3g7f0jn95fn9b/connecting-the-frontend-to-the-api-server-full-stack-google-contacts-clone-with-adonis-js-framework-node-js-and-quasar-framework-vue-js.md)
- [Creating and Updating Contacts From the Frontend | Full-Stack Google Contacts Clone with AdonisJS Framework (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/t15w2s3ao9jo74l96stjo7z6/creating-and-updating-contacts-from-the-frontend-full-stack-google-contacts-clone-with-adonis-js-framework-node-js-and-quasar-framework-vue-js.md)
- [Uploading Files and Creating Avatars for Contacts With AdonisJS and Axios](/llms/technical-blog/article/hg9ilaubqesm8angg0rhrjp9/uploading-files-and-creating-avatars-for-contacts-with-adonis-js-and-axios.md)
- [Deleting a Contact with AdonisJS and Vuejs](/llms/technical-blog/article/zdr4pxmgcax2dsfnwimhty0g/deleting-a-contact-with-adonis-js-and-vuejs.md)

---

## Article Content

In the previous lesson, we learnt how to validate and sanitise our contact data before persisting the data to the database. In this lesson, we will learn how to update a contact and also how to create and configure a middleware in AdonisJS.

Let's start by creating a new branch for our repo:

```bash
# Make sure you are within your project
git checkout -b 14-creating-middlewares-and-updating-a-contact
```

Let's start by creating the route for the contact update request. Open the `api/start/routes.ts` file. Add the line below to the end of the file:

```ts
Route.put('/contacts/:id', 'ContactsController.update')
```

Here we are using the `Route.put()` method which corresponds with the HTTP `PUT` verb to define the route. The `PUT` verb is used when you want to completely override the properties of a resource. This is what we intend to do. It is a bit different from the `PATCH` verb which is used to modify just one property of a resource. Let me explain this better.

Consider this JSON which was used to create a contact in the previous lesson:

```json
{
    "firstName": "Zechariah",
    "surname": "Pollak",
    "company": "Welch, Littel and Rowe",
    "jobTitle": "Account Executive",
    "email1": "zpollak1@blogtalkradio.com",
    "email2": "zpollak1@flickr.com",
    "phoneNumber1": "+66 (700) 444-4282",
    "phoneNumber2": "+237 (446) 364-2728",
    "country": "Thailand",
    "streetAddressLine1": "10327 Pond Pass",
    "streetAddressLine2": "1209 Vermont Drive",
    "city": "Trang",
    "state": null,
    "birthday": "1963-10-15",
    "website": "http://indiegogo.com",
    "notes": null
  }
```

if we want to modify the contact with the `PUT` method, we have to supply the entire JSON in the body of the `update` request. If we omit any property, it will be `undefined` and will persisted into the column as `null`. So, if we want to change the `surname` to `Jamie`; `country` to `Germany`, and `jobTitle` to `Chief Security Officer`, we have send the JSON below as payload:

```json
{
    "firstName": "Zechariah",
    "surname": "Jamie",
    "company": "Welch, Littel and Rowe",
    "jobTitle": "Chief Security Officer",
    "email1": "zpollak1@blogtalkradio.com",
    "email2": "zpollak1@flickr.com",
    "phoneNumber1": "+66 (700) 444-4282",
    "phoneNumber2": "+237 (446) 364-2728",
    "country": "Germany",
    "streetAddressLine1": "10327 Pond Pass",
    "streetAddressLine2": "1209 Vermont Drive",
    "city": "Trang",
    "state": null,
    "birthday": "1963-10-15",
    "website": "http://indiegogo.com",
    "notes": null
  }
```

But why do we have to send the entire properties of the contacts just to update three (3) properties? Well, you might not agree with me but this is a practical answer: delivering all the properties mimics how an edit form works in a real application. If you check the `ui/src/pages/contacts/EditContact.vue` file and edit a contact from the frontend, you will see that the all the properties of the edited contact are logged to the browser console when you submit. On the frontend, resources edit forms are usually designed by populating all the existing data as a reference. Then the user can update the necessary fields and send the changed fields together with the unchanged one back to the server for persistence.

So, what if you want to edit only one property at a time? In that case, you have to define a separate route with a `PATCH` verb. The route might look like this:

```ts
Route.patch('/contacts/:id', 'ContactsController.partialUpdate')
```

And the JSON payload might look like this:

```json
{
   "surname": "Jamie",
}
```

Then, the `partialUpdate` method will be programmed to only update the single property delivered in the JSON.

Back to our route definition for contact update:

```ts
Route.put('/contacts/:id', 'ContactsController.update')
```

The path of the route, `/contacts/:id` contains a `route parameter` named as `id`. A route parameter is used to dynamically match routes and extract parameters from URLs. For example, when we want to update the contact we created in the previous lesson, we will send this request: `PUT /contacts/ckut90fru00013cvohnixd4g0`. AdonisJS will compare the verb (`PUT`) and the path (`/contacts/ckut90fru00013cvohnixd4g0`) with the route definitions in the `routes.ts` file. And then match it with route definition `Route.put('/contacts/:id', 'ContactsController.update')`. After doing this, it will store `ckut90fru00013cvohnixd4g0` in the `params` object as `{id: "ckut90fru00013cvohnixd4g0"}`. The `params` object will then be accessible within the `context` object throughout the lifecycle of that request. More about this latter. Read more about [route parameters](https://docs.adonisjs.com/guides/routing#route-parameters) in AdonisJS.

Continuing with the request lifecycle. When we send the request `PUT /contacts/ckut90fru00013cvohnixd4g0` and the path is matched with the route definition above, AdonisJS will internally instantiate the ContactsController`class and call the`update`instance method. The`update`method will receive the`context`object. The`context` object contains the`params`object. The`context\` object will look like this:

```js
const context = {
   params: {
      id: "ckut90fru00013cvohnixd4g0"
   },
   request: {     
      body: function(){
         return {
           // Unsanitised JSON payload
         }
      }
   },
   response: {//}
}
```

We can access the `id` URL parameter via `context.params.id` and use it to fetch the requested contact from the database.

In this future when we want to fetch a contact and delete a contact, we will define the following routes:

```ts
Route.get('/contacts/:id', 'ContactsController.show') # For fetching the properties of a contact

Route.delete('/contacts/:id', 'ContactsController.destroy') # For deleting a contact
```

Again, within the `show` and `destroy` methods, we will have to repeat the same process of fetch the `id` parameter from `context.params.id` and then lookup the database to get the requested contact before we carry on with the intending operations. This is repetitive. So, what do we do? We need to extract the process of getting the `id` parameter and fetching the requested contact from the database into a separate file. We also need to share the file with all our `put`, `get` and `delete` routes. That file we will extract is called a `middleware`. `Middlewares` are used to perform repetitive tasks which can be shared across multiple routes. A `middleware` can also be used to fetch and inject additional data into our `context` object and have those data available throughout the request lifecycle. This is what we will do now.

## Creating a Middleware

AdonisJS has a command for creating middlewares. Run the command below:

```bash
node ace make:middleware FindContact
```

This command will create a new middleware file under `api/app/Middleware/FindContact.ts`. We need to configure the AdonisJS application to recognise the middleware file. Open `api/start/kernel.ts`. Add the new middleware to the `Server.middleware.registerNamed` function. Refer to this [snaphot file](https://github.com/ndianabasi/google-contacts/blob/14-updating-a-contact/api/start/kernel.ts#L41). Save the file.

```diff
- Server.middleware.registerNamed({})
+ Server.middleware.registerNamed({ findContact: () => import('App/Middleware/FindContact') })
```

We have just created a named middleware. This means that we have to always explicitly call it with the name `findContact` before it is loaded. There is another type of middleware called `global middleware`. Global middleware are automatically loaded during application startup and are available during any request. Read more about [middlewares in AdonisJS](https://docs.adonisjs.com/guides/middleware).

Open the file, then copy-and-paste the content of this [snapshot file](https://github.com/ndianabasi/google-contacts/blob/14-updating-a-contact/api/app/Middleware/FindContact.ts) into the `api/app/Middleware/FindContact.ts` file. Let's discuss what's going on within the middleware file. The content of the middleware file is shown below:

```ts
import Contact from 'App/Models/Contact'
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'

export default class FindContact {
  public async handle(ctx: HttpContextContract, next: () => Promise<void>) {
    // code for middleware goes here. ABOVE THE NEXT CALL
    const { response, params } = ctx
    const { id } = params

    if (!id) {
      return response.badRequest({ message: 'Contact ID not provided' })
    }

    const contact = await Contact.findOrFail(id)
    if (!contact) {
      return response.notFound({ message: 'Unknown contact was requested' })
    }

    ctx.requestedContact = contact

    await next()
  }
}
```

We start by importing the `Contact` model and the `HttpContextContract` interface for type checking. A middleware class must have a `handle` method which is the entry point into the middleware. The `context` object is passed into the `handle` method as the first argument while a `next()` function is passed in as the second argument. Since a middleware is executed after the route definition is called and before the controller method is called, the `next()` function is used to advance or go to the `next` available middleware or if there is no other middleware, the controller method will be called. Therefore, calling the `next()` function after all the operations within the `handle` method is very important. Else, the request lifecycle will be stalled/stopped.

We destructure the `context` (`ctx`) object to get the `response` and `params` objects. The `request` object is not needed in the middleware so we don't extract it from the `context` object. Then, we destructure the `params` object to get the `id` property. If the `id` is not found, we return a 400 (`bad request`) error. We use the findOrFail static method to fetch the requested contact from the database and store it in the `contact` constant. Before calling the next() function, we assign the `contact` object to the `ctx` object through the `requestedContact` property. By doing this, when the request arrives the `ContactsController.update` method, the `requestedContact` will be available in the `context` object and can be destructured from there. Finally, we call the `next()` function. Since `next()` returns a promise, we have to `await` it.

Save the `api/app/Middleware/FindContact.ts` middleware file.

You will definitely get type errors when you assign `requestedContact` to the `ctx` object. Obviously, `requestedContact` is our custom property which is known defined in the `HttpContextContract` interface. We need to make TypeScript to be aware of the `requestedContact` property we are not attaching to the `HttpContextContract` interface.

```bash
# If you are using VS Code
code api/contracts/custom-http-context.ts
```

If you are not using VS Code, manually create the file `api/contracts/custom-http-context.ts` and open it.

Paste the following into the file and save.

```ts
import Contact from 'App/Models/Contact'

declare module '@ioc:Adonis/Core/HttpContext' {
  interface HttpContextContract {
    requestedContact?: Contact
  }
}
```

In the above, we are making use of TypeScript's `declarative merging` to merge our custom interface containing the property: `requestedContact?: Contact` with the origin `HttpContextContract` interface defined by AdonisJS. Save this file. If you check the middleware file now, that type error will be gone.

Now, we will assign the middleware to our `contact update` route.

```ts
Route.put('/contacts/:id', 'ContactsController.update').middleware(['findContact'])
```

## Improving the ContactValidator file

Before we go into our `ContactsController`, let's modify few things in our `ContactValidator` file to suit the update process. Open the `api/app/Validators/ContactValidator.ts` file. Refer to this [snapshot of the file](https://github.com/ndianabasi/google-contacts/blob/14-updating-a-contact/api/app/Validators/ContactValidator.ts#L16-L24). Update Line 18 in the `ContactValidator` file to reflect the highlighted lines in the snapshot.

We intend to make use of the same `ContactValidator` class to validate our data during the `update` process. It will be a duplication to create another. However, we need to modify the schema definition a little bit in order to work smoothly with our `update` process.

For `email1` property, we had the following schema definition:

```ts
...
email1: schema.string({ escape: true, trim: true }, [
      rules.email(),
      rules.unique({ table: 'contacts', column: 'email1', caseInsensitive: false }),
    ]),
...
```

If we keep the schema definition like this, we will get `uniqueness` error on the `email1` field when we want to update a contact because it is merely checking to ensure that `email1` defined in the JSON payload does not exist in the `contacts` table. We have to instruct the `rules.unique` method to excluded the row identified by our `id` from the `uniqueness` check. So, our `email1` property now looks like this:

```ts
...
    email1: schema.string({ escape: true, trim: true }, [
      rules.email(),
      rules.unique({
        table: 'contacts',
        column: 'email1',
        caseInsensitive: true,
        whereNot: this.refs?.id ? { id: this.refs.id } : {},
      }),
    ]),
...
```

The difference is in the `whereNot` property introduced. It checks for the existence of a `refs` instance property defined as shown below:

```ts
  public refs = schema.refs({
    id: this.ctx.params?.id ?? null,
  })
```

Read more about schema `refs` in [Schema Caching in AdonisJS](https://docs.adonisjs.com/guides/validator/schema-caching#using-refs). A `schema refs` is defined calling `schema.refs()` method and assigning an object containing the properties we want to cache as an argument. In the case, we are checking if the `ctx.params` object contains an `id` property. If true, we cache it in the `refs` property and later retrieve it as `this.refs.id`.

Regarding the `whereNot` property in the options for `rules.unique`, if `this.refs.id` exists, we will assign the constraint object `{id: this.refs.id}`. This means that we want to check for uniquenss of entries in the `email1` column of the `contacts` where `contacts.id` is not equal to the `id` of the contact we are edited. This is how you exclude the a resource being edited from uniqueness validation.

## Creating the `ContactsController.update` method

Now that we have ensured that the contact being edited will be validated, we need to work on the `ContactsController.update` method.

Open `api/app/Controllers/Http/ContactsController.ts`. Refer to [this snapshot](https://github.com/ndianabasi/google-contacts/blob/14-updating-a-contact/api/app/Controllers/Http/ContactsController.ts#L85-L141). Let's talk about what going on in the `update` method.

1. At Line 85, do you notice the property `requestedContact` which is destructured from the `context object. That is the property we added to the `context`object in the`FindContact`middleware. Because we calling the middleware in the route definition, the`Lucid`model of the`Contact`will be looked up and stored in the`context\` object.
2. At Line 87, we begin by calling the `request.validate` method and passing in the `ContactValidator` class as the argument. The `validate` method will return the validated and sanitised properties of the JSON data.
   ```ts
      const payload = await request.validate(ContactValidator)
   ```

````
   If validation fails, an error will be thrown and sent back to the client via the `response` object.
3. At Line 89, we destructure `payload` to get the individual properties of the payload.
   ```ts
      const {
        firstName,
        surname,
        company,
        jobTitle,
        email1,
        email2,
        phoneNumber1,
        phoneNumber2,
        country,
        streetAddressLine1,
        streetAddressLine2,
        city,
        postCode,
        state,
        birthday,
        website,
        notes,
      } = payload!
````

4. At Line 109, we merge all the properties from our payload with the existing properties of the `Lucid` model `: requestedContact`. This completely overrides the properties of the `Contact` model accept `id`, `createdAt`, and `updatedAt` properties which we haven't assigned because in the contact update operation, the `id` won't be update; the `createdAt` property is automatically when the contact is first created; and the `updatedAt` property is automatically updated when the contact is updated.
5. At Lines 129-130, we call the static method: `save()` to persist the changes (merged properties) to the database. Notice that that `requestedContact.merge()` method was not `awaited` because it is a synchronous operation which does not involve the database. While the `requestedContact.save()` method was `awaited` because it is an asynchronously call to a database operation and we need to wait for the database engine to carry out the task and return the results. After this we `refresh` the model before returning the response.

## Updating a Contact

Now, we have everything in place to update a contact. Let's do the following:

1. Open `Postman`. Ensure that you are in the `Google Contacts Clone` workspace.

2. Right-click on the `CRUD` collection and click `Add Request`. Enter `Edit Contact` as the name.

3. Change the request method to `PUT`. Enter `{{baseURL}}/contacts/:id` in the`Request URL` field. The `Path Variable` table will be displayed under the `Params` tab. If not show, switch to the `Params` tab below the `request URL` manually. We need to populate the `id` of the contact we want to update.

4. Open `MySQL Workbench` and open the connection we created for this series. Expand the `google_contacts_app` schema, and browse the `contacts` table. Copy the `id` of the contact with `first_name` : `Zechariah`.

5. Now, switch back to `Postman` and paste the `id` into the `VALUE` column for the `id` parameter row. Enter `Contact ID` under `DESCRIPTION`.

   ![image.png](https://cdn.ndianabasi.com/site/creating_a_middleware_and_updating_a_contact_full_stack_google_contacts_clone_with_adonisjs_node_js_and_quasar_framework_vue_js_v1634569226239_3_Rmr_Pto5_Q_ba9243ceab.png)

6. Switch to the `Body` tab. Select `raw` data type and make sure that `JSON` is selected at the end of the options.

   ![image.png](https://cdn.ndianabasi.com/site/creating_a_middleware_and_updating_a_contact_full_stack_google_contacts_clone_with_adonisjs_node_js_and_quasar_framework_vue_js_v1634569805451_e_Y0_Q_Ho_KTG_3d1672caa7.png)

7. Inside the `body` area, copy and paste the JSON below:

   ```json
   ```

{
"firstName": "Zechariah",
"surname": "Jamie",
"company": "Welch, Littel and Rowe",
"jobTitle": "Chief Security Officer",
"email1": "zpollak1@blogtalkradio.com",
"email2": "zpollak1@flickr.com",
"phoneNumber1": "+66 (700) 444-4282",
"phoneNumber2": "+237 (446) 364-2728",
"country": "Germany",
"streetAddressLine1": "10327 Pond Pass",
"streetAddressLine2": "1209 Vermont Drive",
"city": "Trang",
"state": null,
"birthday": "1963-10-15",
"website": "http://indiegogo.com",
"notes": null
}

````

   Click `Beautify` at the top-right corner to format the JSON properly.
8. Click `Send` to send the request. If everything went well, you will get the response below (we are updating the `surname`, `job_title`, and `country` properties):

   ```json
{
    "message": "Contact was edited",
    "data": {
        "id": "ckut90fru00013cvohnixd4g0",
        "first_name": "Zechariah",
        "surname": "Jamie",
        "company": "Welch, Littel and Rowe",
        "job_title": "Chief Security Officer",
        "email1": "zpollak1@blogtalkradio.com",
        "email2": "zpollak1@flickr.com",
        "phone_number1": "+66 (700) 444-4282",
        "phone_number2": "+237 (446) 364-2728",
        "country": "Germany",
        "street_address_line1": "10327 Pond Pass",
        "street_address_line2": "1209 Vermont Drive",
        "city": "Trang",
        "post_code": null,
        "state": null,
        "birthday": "1963-10-15",
        "website": "http://indiegogo.com",
        "notes": null,
        "created_at": "2021-10-16T04:36:48.000+01:00",
        "updated_at": "2021-10-18T16:06:37.000+01:00"
    }
}
````

Also notice that the `surname`, `job_title`, and `country` properties have changed.

9. Click the `Save` button to save your new request.

Congratulations. You have successfully edited a contact with Postman and your API server is working.

This concludes this lesson. In the next lesson, we will learn how to fetch the properties of a contact and delete a contact as well.

Save all your files, commit and merge with the master branch.

```bash
git add .
git commit -m "feat(api): create FindContact middleware, validate, and update contact"
git push origin 14-creating-middlewares-and-updating-a-contact
git checkout master
git merge master 14-creating-middlewares-and-updating-a-contact
git push origin master
```


*This document was generated from the live article page on https://ndianabasi.com/technical-blog/article/oqxzmtgfy1r3oewpnedc7wf6/creating-a-middleware-and-updating-a-contact-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-framework-vue-js • 2026-06-07*
