Introduction
If you work with JavaScript and Node.js, most likely you've already felt the need to do data validation either on the frontend or on the backend.
There are several libraries and several approaches to perform data validation and most of the time we like to use abstractions, however sometimes we really need to define a JSON Schema and then validate the data through that same JSON Schema.
And for that same reason in today's article we are going to use Ajv, in addition to being a validator, it also has several plugins that help us to "extend" the validation criteria.
Prerequisites
Before going further, you are expected to have basic knowledge of these technologies:
- Node
- NPM
- JSON Schema
Getting Started
First let's create our project folder:
mkdir node-ajv
cd node-ajv
npm init -y
In the project's package.json
add the following property:
{
"type": "module",
}
Now, let's install Ajv in our project:
npm install ajv --save
The next step will be to create our JSON Schema, which will be inside the src/
folder in a file called schema.js
:
export const authSchema = {
type: "object",
properties: {
username: {
type: "string",
description: "Username of the user",
},
email: {
type: "string",
description: "Email of the user",
},
password: {
type: "string",
description: "Password of the user",
minLength: 8,
maxLength: 24,
},
},
required: ["username", "email", "password"],
additionalProperties: false,
};
Then we can create the validator.js
, this file will contain the Ajv instance as well as the factory that will be reused whenever we want to create a new validator:
import Ajv from "ajv";
import { inspect } from "util";
const ajv = new Ajv({ allErrors: true });
export const validatorFactory = (schema) => {
const validate = ajv.compile(schema);
const verify = (data) => {
const isValid = validate(data);
if (isValid) {
return data;
}
throw new Error(
ajv.errorsText(
validate.errors?.filter((err) => err.keyword !== "if"),
{ dataVar: "schemaValidation" } + "\n\n" + inspect(data)
)
);
};
return { schema, verify };
};
As you may have noticed, the validatorFactory()
function takes in the arguments the schema
(which corresponds to a JSON Schema) and returns two properties:
-
schema
- A "copy" of the schema that was passed in the function arguments (if you want you can do a deep copy) -
verify
- receives in the arguments the data that we intend to validate and if this same data is valid the validation is successful and is returned, otherwise the error is thrown
For this article to be easily testable, we can create a simple api, first we install the dependencies:
npm install koa @koa/router koa-body --save
Then we create a base api:
import Koa from "koa";
import Router from "@koa/router";
import koaBody from "koa-body";
const app = new Koa();
const router = new Router();
app.use(koaBody());
router.post("/", async (ctx) => {
ctx.body = "Hello, World";
});
app.use(router.routes());
app.listen(3000);
Finally, we can import the schema that was created, as well as the validation factory, then we create a validator called authValidation
and validate the data from the body of the http request. This way:
import Koa from "koa";
import Router from "@koa/router";
import koaBody from "koa-body";
import { validatorFactory } from "./validator.js"; // 👈 added this
import { authSchema } from "./schema.js"; // 👈 added this
const authValidation = validatorFactory(authSchema); // 👈 added this
const app = new Koa();
const router = new Router();
app.use(koaBody());
// 👇 changes have been made here
router.post("/", async (ctx) => {
const body = ctx.request.body;
const data = authValidation.verify(body);
ctx.body = { data };
});
app.use(router.routes());
app.listen(3000);
Now we can make an http request with the POST
at http://localhost:3000
like this:
{
"email": "random@mail.com",
"username": "random",
"password": "randomPaswword"
}
Conclusion
As usual, I hope you enjoyed the article and that it helped you with an existing project or simply wanted to try it out.
If you found a mistake in the article, please let me know in the comments so I can correct it. Before finishing, if you want to access the source code of this article, I leave here the link to the github repository.
Top comments (4)
How to translate errors?
For that you can use this package: github.com/ajv-validator/ajv-i18n
Error customization
If you want to set a custom error message, you can use this: github.com/ajv-validator/ajv-errors