Validate the Fastify input with Joi
Tags: fastify, node, joi
Published: 2024-01-29 17:07:47

---
title: Validate the Fastify input with Joi
published: true
tags: fastify, nodejs, joi
canonical_url: https://backend.cafe/validate-the-fastify-input-with-joi
---

If you are an `hapi` developer, you may know the [`joi`](https://www.npmjs.com/package/joi) library. It is a powerful validation library that allows you to define programmatic schemas for your data and validate them with ease.

One of the hardest things about migrating from `hapi` to `fastify` is the complexity thats involved for you to be able to keep using `joi` for the route's input validation.

But now, thanks to the [`joi-compiler`](https://www.npmjs.com/package/joi-compiler) library, you can use `joi` with `fastify` without any problem!

> **Note** If you have been afraid to use it because it has very few downloads, don't worry it is a new library and I'm the author. And, if you don't know me, I'm a Fastify core maintainer and I'm the co-author of the [Fastify book](https://backend.cafe/fastify-v4-book) too!

The `joi-compiler` module replaces the default `ajv` schema compiler with a `joi`-based one and allows you to use `joi` schemas to validate your data. Let's see how to use it!

## Integrate `joi` with `fastify`

After you have installed the latest `fastify@4` and `joi-compiler` module:

```
mkdir fastify-joi
cd fastify-joi
npm init -y
npm install --save fastify@4 joi-compiler

```

We can create a simple `index.js` file with the following content:

```js
const fastify = require('fastify')
const JoiCompiler = require('joi-compiler')

// Instantiate the compiler
const joiCompilerInstance = JoiCompiler()

// Install it to Fastify
const app = fastify({
  schemaController: {
    bucket: joiCompilerInstance.bucket,
    compilersFactory: {
      buildValidator: joiCompilerInstance.buildValidator
    }
  }
})

// Use it!
const joiSchema = joiCompilerInstance.joi.object({
  foo: joiCompilerInstance.joi.string().required()
})

app.get('/', {
  handler: () => 'Hello World!',
  schema: {
    headers: joiSchema
  }
})

app.listen({ port: 3000 })

```

If you run this code, you will be able to test the `joi` validation with the following command:

```
curl -X GET http://localhost:3000/
# {"statusCode":400,"error":"Bad Request","message":"\"foo\" is required"}

curl -X GET http://localhost:3000/ -H "foo: bar"
# Hello World!

```

As you can see, the `joi` schema is working as expected! In a few lines of code, we have integrated `joi` with `fastify` and we are able to use it to validate the input of your application routes.

## How it works

The `joi-compiler` module is a Fastify schema compiler, it is used by Fastify to build the components during the startup to guarantee the [encapsulated feature](https://backend.cafe/the-complete-guide-to-the-fastify-plugin-system).

For this reason, the `joi-compiler` can be configured in the `schemaController` option during the Fastify application creation.

> **Note**  
> How the [Fastify Schema Controller](https://www.fastify.io/docs/latest/Reference/Server/#schemacontroller) works is out of the scope of this article. But if you want to know more about it, you can read the [Fastify book](https://backend.cafe/fastify-v4-book)!

## How to configure the `joi-compiler`

The `JoiCompiler` accepts an optional configuration object to customize the `joi` instance.

The default configuration is:

```js
const joiCompilerInstance = JoiCompiler({
  // optionally: provide all the JOI options you need
  // Here is all the possible options: https://joi.dev/api/?v=17.9.1#anyvalidatevalue-options
  prefs: {
    stripUnknown: true
  },

  // optionally: an array with custom JOI extensions such as `@joi/date`
  extensions: [
  ],

  // optionally: if you want to use the async validation. Default: false
  asyncValidation: false
})

```

When you instantiate the `joiCompilerInstance`, the returned object has the following properties:

- `buildValidator`: The function to pass to the `schemaController` option of Fastify.

- `bucket`: The `joi` bucket that contains the schemas when you call the `app.addSchema(joiSchema)` method. You can omit this option if you don't use `app.addSchema`.

- `joi`: A customized `joi` instance that contains the installed `extensions`, if there are any. It is a good practice to use this instance to build your schemas.

## How to use `ajv` and `joi` together!

The power of Fastify is that you can use different schema compilers at the same time! Here is an example of how you can learn from the [Fastify book](https://backend.cafe/fastify-v4-book):

```js
const joiCompilerInstance = JoiCompiler()
const app = fastify()

app.post('/ajv', {
  handler: (request) => request.body,
  schema: {
    body: {
      type: 'object',
      properties: {
        toX: { const: 42 },
        toY: { const: 50 }
      }
    }
  }
})

app.register(async function pluginJoi (app, opts) {
  // Install the joi compiler into this encapsulated context!
  app.setSchemaController({
    bucket: joiCompilerInstance.bucket,
    compilersFactory: {
      buildValidator: joiCompilerInstance.buildValidator
    }
  })

  // Let's try to use the external schemas!
  app.addSchema({ $id: 'x', $value: 42 })
  app.addSchema({ $id: 'y', $value: 50 })

  app.post('/joi', {
    handler: (request) => request.body,
    schema: {
      body: Joi.object({
        toX: Joi.ref('$x'),
        toY: Joi.ref('$y')
      })
    }
  })
})

app.listen({ port: 3000 })

```

If you run this code, you will be able to use the `ajv` and `joi` validation in the same application! The `ajv` validation will be used for the `/ajv` route and the `joi` validation will be used for the `/joi` route.

Pretty cool, right?

## Summary

The [`joi-compiler`](https://www.npmjs.com/package/joi-compiler) is a powerful tool that allows you to build and manage `joi` instances for Fastify out of the box in a few lines of code. If you're a `joi` user, `joi-compiler` is definitely worth checking out!

If you enjoyed this article comment, please share and follow [@ManuEomm](https://twitter.com/ManuEomm) on Twitter!