npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

strapi-plugin-validator

v1.3.0

Published

A strapi plugin that implements validations easier with json on routes definition.

Downloads

69

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 is optional 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 be Array, Object or String:

    • 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 section Custom 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 name
  • args[1] : The content-type name
  • args[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 name
  • args[1] : The content-type name
  • args[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 name
  • args[1] : The content-type name
  • args[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 analyzed
  • args[1] : Some value to be compared
  • args[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!