Development Guides





More often than not you will have the need to validate some data that is passed to your plugin, like configuration or data that should be persisted where an invalid format could have serious consequences.

The default validator that ships with Core implements @hapi/joi under the hood to provide an easy to use syntax for building validation schemas.


Before we start, we need to establish what a few recurring variables and imports in this document refer to when they are used.

import { app, Container, Services } from "@arkecosystem/core-kernel";
  • The app import refers to the application instance which grants access to the container, configurations, system information and more.
  • The Container import refers to a namespace that contains all of the container specific entities like binding symbols and interfaces.
  • The Services import refers to a namespace that contains all of the core services. This generally will only be needed for type hints as Core is responsible for service creation and maintenance.


Get an instance of the Validator

const validator: Services.Validation.ValidationService = app

Run the validator’s rules against its data

validator.validate({ username: "johndoe" }, Joi.object({ username: Joi.string() }));

Determine if the data passes the validation rules


Determine if the data fails the validation rules


Get the failed validation rules


Get all of the validation error messages


Returns the data which was valid


Returns the data which was invalid


Get the data under validation



As explained in a previous article it is possible to extend Core services due to the fact that a Manager pattern is used. Lets go over a quick example of how you could implement your own validator.

Implementing the Driver

Implementing a new driver is as simple as importing the validator contract that needs to be satisfied and implement the methods specified in it.

In this example we will use Joi which is a developer experienced focus validation library.

import { Contracts } from "@arkecosystem/core-kernel";

export class MemoryValidator implements Contracts.Validation.Validator {
    private data: JsonObject;
    private resultValue: JsonObject | undefined;
    private resultError: ValidationErrorItem[] | undefined;

    public validate(data: JsonObject, schema: object): void { = data;

        const { error, value } = (schema as AnySchema).validate(;

        this.resultValue = error ? undefined : value;

        if (error) {
            this.resultError = error.details;

    public passes(): boolean {
        return !this.resultError;

    public fails(): boolean {
        return !this.passes();

    public failed(): Record<string, string[]> {
        return this.groupErrors("type");

    public errors(): Record<string, string[]> {
        return this.groupErrors("message");

    public valid(): JsonObject {
        return this.resultValue;

    public invalid(): JsonObject {
        const errors: JsonObject = {};

        for (const error of this.resultError) {
            errors[error.context.key] = error.context.value;

        return errors;

    public attributes(): JsonObject {

    private groupErrors(attribute: string): Record<string, string[]> {
        const errors: Record<string, string[]> = {};

        for (const error of this.resultError) {
            const errorKey: string | number = error.path[0];

            if (!Array.isArray(errors[errorKey])) {
                errors[errorKey] = [];


        return errors;

Implementing the service provider

Now that we have implemented our memory driver for the validation service we can create a service provider to register it.

import { Container, Contracts, Providers, Services } from "@arkecosystem/core-kernel";

export class ServiceProvider extends Providers.ServiceProvider {
    public async register(): Promise<void> {
        const validationManager: Services.Validation.ValidationManager =<Services.Validation.ValidationManager>(

        await validationManager.extend("memory", async () =>

  1. We retrieve an instance of the validation manager that is responsible for managing validation drivers.
  2. We call the extend method with an asynchronous function which is responsible for creating the validator instance.
  3. We call the setDefaultDriver method which will tell Core to use memory as the new default validator.

If you do not call setDefaultDriver you’ll need to manually retrieve the memory store cache instance via app.get<ValidationManager>(ValidationManager).driver("memory").

2021 © | All Rights Reserved
An Product