✨ Basics
Validators

The Validators

Validators in AdonisJS

Validators are crucial for ensuring that the data entering your application is correct and secure. They help you enforce data integrity and can simplify error handling by providing consistent validation.

Creating a Validator

There are two ways to create a validator in AdonisJS.

1. Using the command line

You can create a validator using the command line.

node ace make:validator update_user

This will create a new file in the app/validators folder named update_user.ts.

2. Create a validator manually

You can create a validator manually by creating a new file in the app/validators folder.

app/validators/update_user.ts
import vine from "@vinejs/vine";
import { Infer } from "@vinejs/vine/types";
 
export const updateUserValidator = vine.compile(
  vine.object({
    name: vine.string(),
    surname: vine.string(),
  })
)
 
export type UpdateUser = Infer<typeof updateUserValidator>;

Using Validators in Controllers

Validators are often used within controllers to validate the request data before proceeding with any business logic.


request.all() returns an object containing all the request data, like body, params... We can use this object to validate the data using the validator.

app/account/controllers/account_controller.ts
import { HttpContext } from "@adonisjs/core/http";
import { updateUserValidator } from "../validators/update_user.js";
import { inject } from "@adonisjs/core";
import AccountService from "../services/account_service.js";
 
@inject()
export default class AccountController {
 
  private accountService: AccountService;
 
  constructor(accountService: AccountService) {
    this.accountService = accountService;
  }
 
  async update({ request, response, auth, session, logger }: HttpContext) {
    try {
      const payload = await updateUserValidator.validate(request.all());
      const user = auth.user!;
      await this.accountService.updateUser(user, payload);
      session.flash("toast", {
        type: "success",
        message: "Your account has been successfully updated"
      });
      return response.redirect().toRoute("dashboard.account");
    } catch (error) {
      logger.fatal(error);
      session.flash("errors", "An unexpected error occurred, please try again later or contact the support.");
    }
  }
}

Complex validation

app/products/validators/product_validator.ts
export const updateProductValidator = vine.compile(
  vine.object({
    id: vine.number(),
    name: vine.string().optional(),
    description: vine.string().optional(),
    price: vine.number().optional(),
    currency: vine.string().optional(),
    isPopular: vine.boolean().optional(),
    image: vine.string().optional().optional(),
    isSubscription: vine.boolean()
      .optional()
      .requiredIfAnyExists(["subscriptionPeriod"]),
    
    isActive: vine.boolean().optional(),
 
    subscriptionPeriod: vine.string().in(["day", "week", "month", "year"] as Stripe.Price.Recurring.Interval[])
      .optional()
      .requiredIfAnyExists(["isSubscription"])
  })
);

In this example, we have a more complex validation schema. We have added optional fields, required fields, and conditional fields. This allows us to validate the data based on the specific requirements of our application.

See more

By using validators, you ensure that your application's input data is always consistent and safe to use, minimizing the risk of errors and security vulnerabilities.

Tips! You can generate routes & controllers with already everything imported with the node ace make:module module_name command.