# Data Validation & Sanitisation with AdonisJS | Full-Stack Google Contacts Clone with AdonisJS (Node.js) and Quasar Framework (Vue.js)

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

This lesson explores how to perform data validation and sanitisation in AdonisJS. It includes how to call the validator before storing data to database.

---

## Tags

- [JavaScript](/llms/technical-blog/tag/javascript.md)
- [Nodejs](/llms/technical-blog/tag/nodejs.md)
- [Vuejs](/llms/technical-blog/tag/vuejs.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)** (Current Article)
- [Creating a Middleware and Updating a Contact | Full-Stack Google Contacts Clone with AdonisJS (Node.js) and Quasar Framework (Vue.js)](/llms/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.md)
- [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 last lesson, we learnt how to create a contact by persisting data sent from the body of our API request. The API request was done via Postman. The data was stored on the `contacts` table of our database as sent from Postman without any form of validation and sanitisation. That is a dangerous situation because a malicious actor could deliver and store dangerous contents on our database which can lead to various attacks such as SQL injections and Persisted Cross-Site Scripting. I wrote a [4300 word article on these attack vectors and how to mitigate them](https://tech.ndianabasi.com/how-to-avoid-sql-injections-xss-attacks-and-file-upload-attacks-in-your-web-application). You should read the article as a web developer. It is very important to understand the implications of your development decisions as a developer because they can make or mar your web applications.

In this lesson, we will learn how to validate and sanitise data sent to our API server before persisting the data to the database.

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

```bash
# Make sure you are within your project
git checkout -b 13-validating-and-sanitise-data-before-storage
```

Let's make some few changes to our `Contact` model before we proceed with the validation and sanitisation task.

Firstly, open the `api/app/Models/Contact.ts` file. Refer to [this snapshot](https://github.com/ndianabasi/google-contacts/blob/13-validating-data-before-storage/api/app/Models/Contact.ts). We will change the `birthday` property of the `Contact` model from `string` to a `Luxon` `DateTime` object. This is because we want to change the `birthday` column on our database from being a `string (VARCHAR)` data type to a `DATE` data type. We will also attach the `@column.date()` decorator to the `birthday` property instead of an ordinary `@column()` decorator. The `@column.date()` decorator enables the automatic conversion of the `Luxon` `DateTime` objects to `string` during serialisation to JSON or conversion of `Luxon` `DateTime` objects to JavaScript `Date` object before persistence. We supply the options: `{ autoCreate: false, autoUpdate: false }` to the `@column.date()` decorator so that the `birthday` field is not auto-created or auto-updated from the current time/date during creation or update of the contact .

```diff
-  @column()
-  public birthday?: string | null | undefined
+  @column.date({ autoCreate: false, autoUpdate: false })
+  public birthday?: DateTime | null | undefined
```

We must also make changes to the structure of our `contacts` table. Particularly, we will alter the type of the `birthday` column from `string/VARCHAR` to `DATE`. To do this in AdonisJS, we create need to create a migration file which will hold the changes we want to make in the database.

```bash
cd api # If you are not in the `api` folder, change into iti
node ace make:migration ChangeDataTypeForBirthdayToDate --table=contacts
```

The above command creates a migration file which will alter the `contacts` table. This argument, `ChangeDataTypeForBirthdayToDate`, passed to the `make:migration` command will be used in creating the filename and serves as an easily reminder of what the migration file was meant for. It is recommended that you make the `argument` descriptive when creating a migration file for altering a table.

Refer to [this snapshot](https://github.com/ndianabasi/google-contacts/blob/13-validating-data-before-storage/api/database/migrations/1634040834472_change_data_type_for_birthday_to_dates.ts). Copy-and-paste the entire content of the snapshot file into the newly-created migration file. Check the `api/database/migrations` directory. It should have a name like this: `xxxxxxxxxxxxxx_change_data_type_for_birthday_to_date.ts`

In the migration file:

1. The line:
   ```
   ```

table.date('birthday').alter().index()

````
      Is used to alter the column from a `string` data type to a `date` data type. You must add the modifier `alter()` else the migration process will attempt to create a new column with the same name `birthday` and, obviously, it will fail.
   2. The lines: 
      ```
      table.dropIndex('birthday')
      table.string('birthday').alter()
````

```
  Are used to reverse the migration in the event we will to rollback to previous state where the `birthday` column was a `string` data type. To do this, first, we must drop the index we applied on the `birthday` column and then proceed to alter the column to a `string` data type.
```

## Validating and Sanitising the Contact Data

Now, let's carry on with the main task for this lesson. You might want to study the [introduction to AdonisJS validation first](https://docs.adonisjs.com/guides/validator/introduction).

First, we need to create a validation class/file which will hold the schema for defining the validation rules. AdonisJS has a command for this. Run:

```bash
node ace make:validator Contact
# This will create a validation file named `app/Validators/ContactValidator.ts`
```

Copy the content of this [snapshot file](https://github.com/ndianabasi/google-contacts/blob/13-validating-data-before-storage/api/app/Validators/ContactValidator.ts) and paste in the `app/Validators/ContactValidator.ts` file you just created. Let's discuss what's going on in the file.

1. At Line 1, we must import the `schema` and `rules` objects from `@ioc:Adonis/Core/Validator` package.
2. From Line 7, we create a `public` instance property named `schema`. The `schema` property will hold the schema object created with the `schema.create()` method. The `schema.create(options)` method takes an options object which lists all the properties in our JSON data - in no particular order. The structure of the options for the `create` method must match the structure of your JSON data. For example the JSON for storing a contacts will look like this:

   ```json
   ```

{
"id": "309b20ac-bbcd-4268-b01f-43770527540d",
"firstName": "Hammad",
"surname": "Pulham",
"company": null,
"jobTitle": null,
"email1": "hpulham0@si.edu",
"email2": null,
"phoneNumber1": "+420 (767) 548-7576",
"phoneNumber2": "+86 (442) 396-1670",
"country": null,
"streetAddressLine1": null,
"streetAddressLine2": null,
"city": null,
"postCode": "240022",
"state": null,
"birthday": "1970-03-13",
"website": "http://boston.com",
"notes": null,
},

````

   The `options` object must reflect the JSON data as shown below:

   ```ts
{
    firstName: schema.string({ escape: true, trim: true }, [rules.maxLength(30)]),
    surname: schema.string({ escape: true, trim: true }, [rules.maxLength(30)]),
    company: schema.string.optional({ escape: true, trim: true }),
    jobTitle: schema.string.optional({ escape: true, trim: true }),
    email1: schema.string({ escape: true, trim: true }, [
      rules.email(),
      rules.unique({ table: 'contacts', column: 'email1', caseInsensitive: false }),
    ]),
    email2: schema.string.optional({ escape: true, trim: true }, [rules.email()]),
    phoneNumber1: schema.string({ escape: true, trim: true }, [rules.maxLength(20)]),
    phoneNumber2: schema.string.optional({ escape: true, trim: true }, [rules.maxLength(20)]),
    country: schema.string.optional({ escape: true, trim: true }, [rules.maxLength(20)]),
    streetAddressLine1: schema.string.optional({ escape: true, trim: true }),
    streetAddressLine2: schema.string.optional({ escape: true, trim: true }),
    city: schema.string.optional({ escape: true, trim: true }),
    postCode: schema.string.optional({ escape: true, trim: true }),
    state: schema.string.optional({ escape: true, trim: true }),
    birthday: schema.date.optional({ format: 'yyyy-MM-dd' }, [rules.before('today')]),
    website: schema.string.optional({ trim: true }, [
      rules.url({
        protocols: ['http', 'https'],
        requireHost: true,
      }),
    ]),
    notes: schema.string.optional({ escape: true, trim: true }),
  }
````

The value of each property in the `options` object must be a schema type such as `string`, `boolean`, `number`, `date`, `enum/enumSet`, `file`, `array`, or `object`. Read more about schema types [here](https://docs.adonisjs.com/reference/validator/schema/string). For example: the `firstName` property is assigned a `schema.string` type which is actually a method of the `schema` object. Each schema type can be chained to an `optional()` modifier which marks the property as being optional. Schema types with no `optional()` modifier are `required` by default. The `string` method takes two argument: `options` and `rules`. The `options` argument of a schema type is usually used for providing the sanitisation options for the property. In this case, we want to escape any value assigned to the `firstName` property. Escaping values means that we want to convert any unsafe character into there `ASCII` representations so that if they were meant for malicious intents, they will become ineffective. (Again, I encourage you to read this detailed article: [How to Avoid SQL Injections, XSS Attacks, and File Upload Attacks in your Web Application](https://tech.ndianabasi.com/how-to-avoid-sql-injections-xss-attacks-and-file-upload-attacks-in-your-web-application).) You the value for `firstName` included a `%` symbol, it will be converted to `&#x25;`. The `rules` argument of the schema type is used to provide the validation rules for the schema type. Rules must be wrapped in an array. For example, for `firstName`, we are setting the `maxLength` rule to `30` characters. For the `email1` and `email2` properties, we set the `email` validation rules so that only valid email addresses will be allowed. The `trim` properties in the schema type options is used to remove all whitespaces at the beginning and end of the values.

The `unique` validation rule assigned to the `email1` property is worthy of special explanation. Here, we are enforcing uniqueness of email addresses for column `email1` on the `contacts` table. We are assuming here that this app will be used for personal purposes and email addresses should be unique. The `unique` rule take some arguments: `table`, `column`, `caseInsensitive`, etc. See the [full description of the unique rule](https://docs.adonisjs.com/reference/validator/rules/unique). The `table` property provides the table which contains the `column` where we want to enforce the uniqueness constraint. The `caseInsensitive` property indicates that the values stored on the `column` are `case insensitive`. Meaning that `Abc@Example.com` will be the same as `abc@example.com`. It should be mentioned that while you can set the `email1` column as `unique` while creating the table, it is important to validate for the same uniqueness separately via a validator rule.

The `birthday` property takes a date schema type with a single property in the options: `format`. The `date` schema type will convert the date string received from the JSON to a `Luxon` DateTime`object. The`format`object is used to specify the format of the date expected in the JSON. For our purpose, the Date component on the frontend will send the date in the`yyyy-MM-dd`format. We also applied a rule which limits the dates to all dates before`today\`. Read more about the [date schema type](https://docs.adonisjs.com/reference/validator/schema/date).

The `website` property is assigned a `string` schema type with a `url` rule. The `url` rule enforces that either `http` or `https` protocol must be provided in the `website` value. It also enforces that the host portion of the URL is required. This means that you cannot provided this: /about-us`as a valid URL. See all the options for the`url\` rule [here](https://docs.adonisjs.com/reference/validator/rules/url).

3. We must also define a public `messages` instance property which will hold all the validation messages which will be sent via API response if the validation fails. Read more about [validation messages](https://docs.adonisjs.com/guides/validator/custom-messages).

Let's proceed to integrate the `ContactValidator` class into the `store` method of the `ContactsController` class.

## Integrating a Validator into a Controller

The validator class on its own will do nothing. For it to work, it has to be initialised and called. For our purpose, we want to call it before the contact is being saved. If you recall from our `api/start/routes.ts` file, the route for creating a contact is defined as shown below:

```ts
Route.post('/contacts', 'ContactsController.store')
```

So, we need to modify the `store` method within the `ContactsController` file. Open `api/app/Controllers/Http/ContactsController.ts`. Refer to this [snapshot file](https://github.com/ndianabasi/google-contacts/blob/13-validating-data-before-storage/api/app/Controllers/Http/ContactsController.ts) for changes to be made.

1. At Line 3, we will import the `Logger` instance from `@ioc:Adonis/Core/Logger` package. It will be used for error logging in the `catch` statement.

2. At Line 4, we will import the `ContactValidator` class from `App/Validators/ContactValidator` file.

3. We will modify the body of the `store` method by wrapping the statements in `try...catch` statements.

4. At Line 11, we call the `request.validate` method and provide the `ContactValidator` class we imported as the argument of the `validate` method. The result of the validator is stored in the `payload` constant. The `payload` constant will contain our validated and sanitised properties from our JSON data provided in the request body. The `validate` method instantiates the class internally and makes use of the `schema` and `messages` properties in the `ContactValidator` class to perform the validator. If the validation fails, an error will be thrown using the relevant validation messages defined. We will manually `catch` these validation error in the `catch` statement and return the error as a response to the frontend.  Read more [here](https://docs.adonisjs.com/guides/validator/introduction#using-validator).

5. From Line 25, we destructure the `payload` to obtain the properties we want to save. Other parts of the `store` method remain the same.

6. In the `catch` statement - from Line 73, we log any error in the `store` method to the console. Then return the response with the error. First, we check if the `error` object contains a `status` property which represents the status code for the error. If there is a `status` property, that status code will be used in the response. For validation errors, the status code is `422`. Learn more about [API status codes](https://restfulapi.net/http-status-codes/). If the error contains no status codes, we will use 500 as a generic internal server error code in the response. We also check if the app is not used in production or `error.status` is `422`. If not `true`, we do not include the error object in the error property. These are security measures to ensure that you do not spit out sensitive error contents to the frontend. As a developer, you should use the console to log and check error messages and avoid sending them to the frontend (unless you are not in production mode). You can also send errors via email for record purposes.

## Testing the Validation with Postman

Let's test our `ContactValidation` validator by sending API requests through Postman.

1. Open `Postman`. Ensure that you are in the `Google Contacts Clone` workspace. We had created a request named: `Create Contact` with URL `POST /contacts` in the previous lesson. We are still using the JSON below for the request.

```json
{
    "firstName": "Hammad",
    "surname": "Pulham",
    "email1": "hpulham0@si.edu",
    "phoneNumber1": "+420 (767) 548-7576",
    "phoneNumber2": "+86 (442) 396-1670",
    "birthday": "1970-03-13",
    "website": "http://boston.com"
}
```

2. Click on the `Create Contact` request to open it. Then click the `Send` button to send the request. If the contact in the JSON had been created before, you will get an error like this:

   ```json
   ```

{
"message": "An error occurred while creating the contact.",
"error": {
"flashToSession": false,
"messages": {
"errors": \[
{
"rule": "unique",
"field": "email1",
"message": "Email 1 is already registered in your contacts"
}
]
}
}
}

````

   Congratulations, your validation is working.

2. Now, change the value for `website` to `boston.com` and resend the request. You will get an error like this:

   ```json
{
    "message": "An error occurred while creating the contact.",
    "error": {
        "flashToSession": false,
        "messages": {
            "errors": [
                {
                    "rule": "unique",
                    "field": "email1",
                    "message": "Email 1 is already registered in your contacts"
                },
                {
                    "rule": "url",
                    "field": "website",
                    "message": "Website is not valid"
                }
            ]
        }
    }
}
````

Now, we have two validation messages.

3. Remove the `firstName` field and resend the request. You should get an error like this:

   ```json
   ```

{
"message": "An error occurred while creating the contact.",
"error": {
"flashToSession": false,
"messages": {
"errors": \[
{
"rule": "required",
"field": "firstName",
"message": "First Name is required"
},
{
"rule": "unique",
"field": "email1",
"message": "Email 1 is already registered in your contacts"
},
{
"rule": "url",
"field": "website",
"message": "Website is not valid"
}
]
}
}
}

````

4. Now, update the JSON body to the JSON below and resend the request:

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

A new contact should be created because all validations were successfully:

```json
{
 "message": "Contact was created",
 "data": {
     "id": "ckut90fru00013cvohnixd4g0",
     "first_name": "Zechariah",
     "surname": "Pollak",
     "company": "Welch, Littel and Rowe",
     "job_title": "Account Executive",
     "email1": "zpollak1@blogtalkradio.com",
     "email2": "zpollak1@flickr.com",
     "phone_number1": "+66 (700) 444-4282",
     "phone_number2": "+237 (446) 364-2728",
     "country": "Thailand",
     "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-16T04:36:48.000+01:00"
 }
}
```

Save the `Create Contact` request in Postman.

## Difference between JSON and JavaScript Object.

The main difference is that you must wrap the properties of JSON object with double quotes (single quotes are not accepted). Example:

```json
{
 "message": "Contact was created",
 "data": {
     "id": "ckut90fru00013cvohnixd4g0",
     "first_name": "Zechariah",
 }
}
```

While the property of a JavaScript object is only wrapped with double or single quotes when the property is a compound word. Example:

```ts
{
 'firstName.required': 'First Name is required',
 'firstName.maxLength': 'First Name should be maximum of {{options.maxLength}} characters.',
}
```

This concludes our lesson. In the next lesson, we will learn how to update and delete a contact.

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

```bash
git add .
git commit -m "feat(api): complete validation of contacts data before storage"
git push origin 13-validating-and-sanitise-data-before-storage
git checkout master
git merge master 13-validating-and-sanitise-data-before-storage
git push origin master
```


*This document was generated from the live article page on https://ndianabasi.com/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 • 2026-06-07*
