Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Validation with VineJS

Form data cannot be trusted: the title may be left empty, and a number field may receive text. Validation is checking incoming data against rules before it reaches the database. AdonisJS uses the VineJS library for this: rules are described as a schema, and the result of the check gets exact TypeScript types.

Creating a validator

node ace make:validator post

The file app/validators/post.ts appears. Describe the rules for a new post:

// app/validators/post.ts
import vine from '@vinejs/vine'
 
export const createPostValidator = vine.compile(
  vine.object({
    title: vine.string().trim().minLength(3).maxLength(255),
    body: vine.string().trim().minLength(10),
  })
)

vine.object describes the expected fields, vine.string() requires a string, and trim, minLength and maxLength refine the rules. vine.compile turns the schema into a fast check function once. All fields are required by default.

Checking in a controller

// app/controllers/posts_controller.ts
import type { HttpContext } from '@adonisjs/core/http'
import Post from '#models/post'
import { createPostValidator } from '#validators/post'
 
export default class PostsController {
  async store({ request, response }: HttpContext) {
    const payload = await request.validateUsing(createPostValidator)
    const post = await Post.create(payload)
    return response.redirect().toRoute('posts.show', { id: post.id })
  }
}

validateUsing takes the request data and checks it. If everything is valid, payload contains only the described fields, typed as { title: string; body: string }. Extra fields, such as isAdmin, do not get into it.

What happens on an error

If the check fails, the code after validateUsing does not run. Then AdonisJS acts according to the request type:

RequestResponse
A regular HTML formA redirect back, errors and entered values are saved in the session
A JSON request (header Accept: application/json)Status 422 and JSON with the list of errors

How to show errors next to form fields is covered in the next lesson.

Common rules

RuleWhat it checks
vine.string().email()An email address
vine.number().min(1)A number not less than 1
vine.boolean()Yes or no, including a form checkbox
vine.enum(['draft', 'published'])One of the values
vine.string().optional()The field may be omitted
vine.string().confirmed()Matches the ..._confirmation field

Custom messages

You can replace the standard VineJS messages with your own texts through a messages provider. Create a preload file with node ace make:preload validator and write in it:

// start/validator.ts
import vine, { SimpleMessagesProvider } from '@vinejs/vine'
 
vine.messagesProvider = new SimpleMessagesProvider({
  'required': 'The {{ field }} field is required',
  'minLength': 'The {{ field }} field must be at least {{ min }} characters',
  'title.minLength': 'The title is too short',
})

The title.minLength key sets a message for one field and one rule, and the general minLength key covers all the others.

Common mistake

A validator is created inside a controller method: const validator = vine.compile(...) right in store. Then the schema is compiled again on every request, which noticeably slows the application down. Declare validators in app/validators/ at the top level of the module, and import the ready ones into the controller.

Thanks for reading!

Donate to the site — we work hard for you.