strapi-plugin-validator
v1.3.0
Published
A strapi plugin that implements validations easier with json on routes definition.
Downloads
36
Maintainers
Readme
strapi-plugin-validator
🚀 Overview
This plugins was created on top of Indicative project, mantained by Adonis.js with the purpose to keep simple the management of validations on Strapi Projects. Also, this enriches the standard validation of the strapi content-types, including a better response structure to frontend.
⏳ Installation
With npm:
npm install strapi-plugin-validator
With yarn:
yarn add strapi-plugin-validator
Changes in yours strapi project strucutre.
This plugin doesn't need many changes in yours project, so dont be worry because it should not broke.
1.0 - The file validators.json
To allow this plugin integrate with your project, all you need is create a new file called validators.json
inside yours content-types
, extensions
or plugins
folders like below:
--- api/
--- your-content-type/
--- config/
validators.json
--- extensions/
--- installed-plugin-name/
--- config/
validators.json
--- plugins/
--- your-custom-plugin/
--- config/
validators.json
1.1 - The content of file validators.json
Once you determine the better place where you want to write your validator based in your self purposes, its time to create its content. For this example, i will create a custom validator for user (created by users-permission plugin) placed in extensions
folder, it because strapi validator is a bit poor and i want to create a better validation for custom fields that i can create in my user content-type.
So below, you can see the structure of this file.
{
"validators": {
"user": {
"message":"It appears that there is some invalid information on your user.",
"rules": {
//Example with Array Structure
//[the basic approach]
"email": [
"required",
"email"
],
//Example with Object Structure
//[approach with custom messages]
"password": {
"required": "The password is the most important!!",
"min:4": "And must to have a minimal 4 character length!!"
},
//Example with String Structure
//[approach referring to another validator as a deep level validation]
"address": "api.address.config.validators.address"
}
}
}
}
As you can see, it is not so hard to understand, so lets explain each property, on-by-one.
validators
:This is a mandatory property needed by plugin, its because strapi expose configs for each content-type, and the plugin needs to find validators inside this configs. How this is an object, you can create many validators inside it to serve several purposes.
validators
/ [user
]:[
user
] its only an identifier for your validator, so it could by any name, you will need this to relate a validator to another validator if the validation has a deep level object to validate. Also, this identifier will be used on routes to define whitch route will need to be validated by your validator.validstors
/ [user
] /message
:The property
message
isoptional
and its value should be a message to frontend explaining a generic fail information for this request. If this is not informed, the default message is "Bad Request
"validstors
/ [user
] /rules
:The property
rules
content must to be a object following the rules of indicative project, to see all allowed validation rules, read this link. Each rule can have three types of value structure, and for each structure, there is a different behavior, the types of structure can beArray
,Object
orString
:Array
: The Array is the most basic approach of validation, each item of the array must to be a string identifying the validation rule (that you can find accessing the indicative project) or reading the customized validations on the sectionCustom Validation
on this documentation.Object
: The Object also implements validations, but different from the Array, the rule must be identified in the object's key, leaving the value of that key free for you to create a customized message for your users.String
: The String value must to be a path to another validator using dot notation, allowing you to create deep level validations and reuse these validations in other validators.
2.0 - The file routes.json
Finally, we need to append the validator to some route who need to pass by validation. To do it is very simple and for that i will use the same example of user
model like before. In this case i will need to recreate a file routes.json
on extensions/users-permissions/config
to override the default route config of users-permission plugin:
{
"routes": [
{
"method": "POST",
"path": "/auth/local/register",
"handler": "Auth.register",
"config": {
"policies": [
"plugin::users-permissions.ratelimit"
],
"prefix": "",
"description": "Register a new user with the default role",
"tag": {
"plugin": "users-permissions",
"name": "User",
"actionType": "create"
},
"validate": "plugins.users-permissions.config.validators.user"
}
}
]
}
Here, i has copied all content of routes of users-permissions
plugin and added a new property validate
inside routes.[0].config
, basically the value of validate
property is the path to the validators.json
and the identifier
of validator inside this file on the end.
In additional, you can use the property validate_ignore_required
as true
to indicate that this route doesn't need fields to be required, so in your requests for update data, any field will not be required and you can pass only needed fields to update.
The frontend result.
Well, if you knows the basic valdiation of strapi, may you know that the result of this validation is not so friendly to frontend, some of theses problems is a single validation by request (response returns when the first validation fails
), and a response object pattern that doesn't tell to frontend the exact field who fails (the frontend needs to treat the value of each property id to knows the failed field
) like example below:
{
"statusCode": 400,
"error": "Bad Request",
"message": [
{
"messages": [
{
"id": "Auth.form.error.email.taken",
"message": "Email is already taken."
}
]
}
]
}
This plugin uses the indicative response pattern, that presents to forntend exacly what it needs to know about the field
, validation error type
and message
.
{
"statusCode": 400,
"error": "Bad Request",
"message": "It appears that there is some invalid information on your user form.",
"data": [
{
"message": "Email is already in use.",
"validation": "unexists",
"field": "email"
}
]
}
Custom validations
This plugin implements other usually validations that indicative doest support by default.
unexists
It checks if the requested field value does not exists inside some content-type and return an error if this value is founded on database.
Example.:
Check if the email is available for use."rules": { "email": [ "unexists:email,user,users-permissions" ] }
args[0]
: The content-type column nameargs[1]
: The content-type nameargs[2]
: Is optional, verify the plugin where content-type resides
available
Like unexists rule, it checks if the requested field value does not exists inside some content-type and return an error if this value is founded on database, but with differencial that if you are trying to update a record that belongs to you with the same value, it will allow the update, preventing a throwing error becouse you self record already exists.
Example.:
Check if the email is available on update, but allow you to update its email if it belongs to you."rules": { "email": [ "available:email,user,users-permissions" ] }
args[0]
: The content-type column nameargs[1]
: The content-type nameargs[2]
: Is optional, verify the plugin where content-type resides
valid_password
It throws an error if the field does not contains the same password as the authenticated user (user.users-permissions) plugin. It can helps you to update password without need to create policies or new controllers.
"rules": { "current_password": { "valid_password": "The current password provided is invalid.", } }
exists
It checks if the requested field value exists inside some content-type and return an error if this value is not founded on database.
Example.:
Check if the plan id informed by user exists on database."rules": { "plan": [ "exists:id,plan" ] }
args[0]
: The content-type column nameargs[1]
: The content-type nameargs[2]
: Is optional, verify the plugin where content-type resides
empty
It checks if the requested field value is empty and return an error if it is true.
Example.:
The name is not undefined, but is an empty string, so it checks if is an string with zero length."rules": { "name": [ "empty" ] }
invalid_when
It throws an error if the first parameter (another field on the payload) has some of one values on the next other (n params).
Example.:
Imagine a register of property, the field garden only can be filled if it is a common house, otherwise like (apartment or yatch) it cannot have a garden."rules": { "garden": [ "invalid_when:property_type,apartment,yacht" ] }
args[0]
: Another field on payload to be analyzedargs[1]
: Some value to be comparedargs[n]
: More values to be compared
objectid
It throws an error if the value passed is not a valid ObjectId (validated by mongoose).
Example.:
Strapi brokes when you pass an invalid ObjectId to it, so you can validate and send a message to user before it happens."rules": { "plan": [ "objectid" ] }
file
It throws an error if the value passed is not a valid file.
Example.:
The registered user must to provide an avatar picture and the upload must to be an image."rules": { "avatar": [ "file:image" ] }
args[0]
: The file type (image|video|any)
datetime
It throws an error if the value passed does not match a specified valid date pattern.
Example.:
The registered user must to provide its birthday with hour and minute."rules": { "avatar": [ "datetime:yyyy-MM-dd HH:mm" ] }
args[0]
: The date pattern to match (default is yyyy-MM-dd HH:mm)
e164
It throws an error if the value passed does not match the global format pattern e.164 for phones.
Example.:
The registered user must to provide a valid phone number."rules": { "phone": [ "e164" ] }
brphone
It throws an error if the value passed does not match the brazilian phone number pattern "0000000000" or "00900000000" | (without mask).
Example.:
The registered user must to provide a valid brazilian phone number."rules": { "phone": [ "brphone" ] }
cep
It throws an error if the value passed does not match the brazilian zipcode number pattern "00000000" | (without mask).
Example.:
The registered user must to provide a valid brazilian zipcode number."rules": { "zipcode": [ "cep" ] }
cnpj
It throws an error if the value passed was not a valid brazilian company registry number (CNPJ) | (without mask).
Example.:
The registered user must to provide its valid company registry number."rules": { "document": [ "cnpj" ] }
cpf
It throws an error if the value passed was not a valid brazilian personal registry number (CPF) | (without mask).
Example.:
The registered user must to provide its valid company registry number."rules": { "document": [ "cpf" ] }
cpfj
It throws an error if the value passed was not a valid brazilian personal registry number (CPF) or brazilian company registry number (CNPJ) | (without mask).
Example.:
The registered user must to provide its valid company registry number."rules": { "document": [ "cpfj" ] }
🎉 Congradulations, You're done.
How can you see, is not so hard to implement custom validations with this plugin, and if you have been followed step-by-step of this documentation, you probably now can implement youself validations and make your project easy. I hope to have been made it simple for you understand and that this project helps you in your own project.
📜 License
This project is under the MIT license. See the LICENSE for details.
💻 Developed by André Ciornavei - Get in touch!