# express-joi-validation

> validate express application inputs and parameters using joi

Latest version **6.1.0** (published 2025-05-27) · MIT license · 0 weekly downloads

## Install

```sh
npm install express-joi-validation
pnpm add express-joi-validation
yarn add express-joi-validation
bun add express-joi-validation
```

## Health

**Score 35/100 (D)** — status: maintenance-mode.

Positive: has types; no vulnerabilities; high quality score.

Warnings: low downloads; no esm support.

Negative: stale; low maintenance score.

## Facts

| | |
|---|---|
| Version | 6.1.0 |
| Published | 2025-05-27 |
| First published | 2017-04-17 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | CommonJS |
| Node | >=18.0.0 |
| Dependencies | 0 |
| Unpacked size | 21.4 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 103 |
| Author | Evan Shortiss |
| Maintainers | evanshortiss |
| Keywords | joi, express, validation, middleware, typescript, tsc |

## Links

- npm: https://www.npmjs.com/package/express-joi-validation
- Repository: https://github.com/evanshortiss/express-joi-validation
- Homepage: https://github.com/evanshortiss/express-joi-validation#readme
- Issues: https://github.com/evanshortiss/express-joi-validation/issues
- npm.io page: https://npm.io/package/express-joi-validation

## Alternatives

- [@regle/core](https://npm.io/package/@regle/core.md) — 47.0K weekly downloads
- [typeof-arguments](https://npm.io/package/typeof-arguments.md) — 12.5K weekly downloads
- [@lokalise/projects-engine-contracts](https://npm.io/package/@lokalise/projects-engine-contracts.md) — 978 weekly downloads
- [@osjwnpm/nam-laboriosam-quibusdam](https://npm.io/package/@osjwnpm/nam-laboriosam-quibusdam.md) — 70 weekly downloads
- [@oridune/validator](https://npm.io/package/@oridune/validator.md) — 16 weekly downloads

## Recent versions

- 6.1.0 (latest) — 2025-05-27
- 6.0.0 — 2024-12-13
- 5.0.1 — 2021-12-21
- 5.0.0 — 2020-10-13
- 4.0.4-beta.0 — 2020-07-15
- 4.0.3 — 2019-11-18
- 4.0.2 — 2019-11-12
- 4.0.1 — 2019-09-24
- 4.0.0 — 2019-09-20
- 3.0.0 — 2019-08-30
- 2.0.1 — 2019-08-21
- 2.0.0 — 2019-06-27
- 1.0.0 — 2019-06-17
- 0.3.0 — 2018-09-29
- 0.2.1 — 2017-10-28
- … 2 more at https://npm.io/package/express-joi-validation/versions

## README

# express-joi-validation

![TravisCI](https://travis-ci.org/evanshortiss/express-joi-validation.svg)
[![Coverage Status](https://coveralls.io/repos/github/evanshortiss/express-joi-validation/badge.svg?branch=master)](https://coveralls.io/github/evanshortiss/express-joi-validation?branch=master)
[![npm version](https://badge.fury.io/js/express-joi-validation.svg)](https://www.npmjs.com/package/express-joi-validation)
[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-blue.svg)](http://www.typescriptlang.org/)
[![npm downloads](https://img.shields.io/npm/dm/express-joi-validation.svg?style=flat)](https://www.npmjs.com/package/express-joi-validation)
[![Known Vulnerabilities](https://snyk.io//test/github/evanshortiss/express-joi-validation/badge.svg?targetFile=package.json)](https://snyk.io//test/github/evanshortiss/express-joi-validation?targetFile=package.json)

A middleware for validating express inputs using Joi schemas. Features include:

* TypeScript support.
* Specify the order in which request inputs are validated.
* Replaces the incoming `req.body`, `req.query`, etc and with the validated result 
* Retains the original `req.body` inside a new property named `req.originalBody`.
. The same applies for headers, query, and params using the `original` prefix,
e.g `req.originalQuery`
* Chooses sensible default Joi options for headers, params, query, and body.
* Uses `peerDependencies` to get a Joi instance of your choosing instead of
using a fixed version.

## Quick Links

* [API](#api)
* [Usage (JavaScript)](#usage-javascript)
* [Usage (TypeScript)](#usage-typescript)
* [Behaviours](#behaviours)
  * [Joi Versioning](#joi-versioning)
  * [Validation Ordering](#validation-ordering)
  * [Error Handling](#error-handling)
  * [Joi Options](#joi-options)
  * [Custom Express Error Handler](#custom-express-error-handler)

## Install

You need to install `joi` with this module since it relies on it in
`peerDependencies`.

```
npm i express-joi-validation joi --save
```

## Example
A JavaScript and TypeScript example can be found in the `example/` folder of
this repository.

## Usage (JavaScript)

```js
const Joi = require('joi')
const app = require('express')()
const validator = require('express-joi-validation').createValidator({})

const querySchema = Joi.object({
  name: Joi.string().required()
})

app.get('/orders', validator.query(querySchema), (req, res) => {
  // If we're in here then the query was valid!  
  res.end(`Hello ${req.query.name}!`)
})
```

## Usage (TypeScript)

For TypeScript a helper `ValidatedRequest` and
`ValidatedRequestWithRawInputsAndFields` type is provided. This extends the
`express.Request` type and allows you to pass a schema using generics to
ensure type safety in your handler function.

```ts
import * as Joi from 'joi'
import * as express from 'express'
import {
  ContainerTypes,
  // Use this as a replacement for express.Request
  ValidatedRequest,
  // Extend from this to define a valid schema type/interface
  ValidatedRequestSchema,
  // Creates a validator that generates middlewares
  createValidator
} from 'express-joi-validation'

const app = express()
const validator = createValidator()

const querySchema = Joi.object({
  name: Joi.string().required()
})

interface HelloRequestSchema extends ValidatedRequestSchema {
  [ContainerTypes.Query]: {
    name: string
  }
}

app.get(
  '/hello',
  validator.query(querySchema),
  (req: ValidatedRequest<HelloRequestSchema>, res) => {
    // Woohoo, type safety and intellisense for req.query!
    res.end(`Hello ${req.query.name}!`)
  }
)
```

You can minimise some duplication by using [joi-extract-type](https://github.com/TCMiranda/joi-extract-type/).

_NOTE: this does not work with Joi v16+ at the moment. See [this issue](https://github.com/TCMiranda/joi-extract-type/issues/23)._

```ts
import * as Joi from 'joi'
import * as express from 'express'
import {
  // Use this as a replacement for express.Request
  ValidatedRequest,
  // Extend from this to define a valid schema type/interface
  ValidatedRequestSchema,
  // Creates a validator that generates middlewares
  createValidator
} from 'express-joi-validation'

// This is optional, but without it you need to manually generate
// a type or interface for ValidatedRequestSchema members
import 'joi-extract-type'

const app = express()
const validator = createValidator()

const querySchema = Joi.object({
  name: Joi.string().required()
})

interface HelloRequestSchema extends ValidatedRequestSchema {
  [ContainerTypes.Query]: Joi.extractType<typeof querySchema>

  // Without Joi.extractType you would do this:
  // query: {
  //   name: string
  // }
}

app.get(
  '/hello',
  validator.query(querySchema),
  (req: ValidatedRequest<HelloRequestSchema>, res) => {
    // Woohoo, type safety and intellisense for req.query!
    res.end(`Hello ${req.query.name}!`)
  }
)
```

## API

### Structure

* module (express-joi-validation)
  * [createValidator(config)](#createvalidatorconfig)
    * [query(options)](#validatorqueryschema-options)
    * [body(options)](#validatorbodyschema-options)
    * [headers(options)](#validatorheadersschema-options)
    * [params(options)](#validatorparamsschema-options)
    * [response(options)](#validatorresponseschema-options)
    * [fields(options)](#validatorfieldsschema-options)

### createValidator(config)
Creates a validator. Supports the following options:

* passError (default: `false`) - Passes validation errors to the express error
hander using `next(err)` when `true`
* statusCode (default: `400`) - The status code used when validation fails and
`passError` is `false`.

#### validator.query(schema, [options])
Creates a middleware instance that will validate the `req.query` for an
incoming request. Can be passed `options` that override the config passed
when the validator was created.

Supported options are:

* joi - Custom options to pass to `Joi.validate`.
* passError - Same as above.
* statusCode - Same as above.

#### validator.body(schema, [options])
Creates a middleware instance that will validate the `req.body` for an incoming
request. Can be passed `options` that override the options passed when the
validator was created.

Supported options are the same as `validator.query`.

#### validator.headers(schema, [options])
Creates a middleware instance that will validate the `req.headers` for an
incoming request. Can be passed `options` that override the options passed
when the validator was created.

Supported options are the same as `validator.query`.

#### validator.params(schema, [options])
Creates a middleware instance that will validate the `req.params` for an
incoming request. Can be passed `options` that override the options passed
when the validator was created.

Supported options are the same as `validator.query`.

#### validator.response(schema, [options])
Creates a middleware instance that will validate the outgoing response.
Can be passed `options` that override the options passed when the instance was
created.

Supported options are the same as `validator.query`.

#### validator.fields(schema, [options])
Creates a middleware instance that will validate the fields for an incoming
request. This is designed for use with `express-formidable`. Can be passed
`options` that override the options passed when the validator was created.

The `instance.params` middleware is a little different to the others. It _must_
be attached directly to the route it is related to. Here's a sample:

```js
const schema = Joi.object({
  id: Joi.number().integer().required()
});

// INCORRECT
app.use(validator.params(schema));
app.get('/orders/:id', (req, res, next) => {
  // The "id" parameter will NOT have been validated here!
});

// CORRECT
app.get('/orders/:id', validator.params(schema), (req, res, next) => {
  // This WILL have a validated "id"
})
```

Supported options are the same as `validator.query`.

## Behaviours

### Joi Versioning
This module uses `peerDependencies` for the Joi version being used.
This means whatever `joi` version is in the `dependencies` of your
`package.json` will be used by this module.


### Validation Ordering
Validation can be performed in a specific order using standard express
middleware behaviour. Pass the middleware in the desired order.

Here's an example where the order is headers, body, query:

```js
route.get(
  '/tickets',
  validator.headers(headerSchema),
  validator.body(bodySchema),
  validator.query(querySchema),
  routeHandler
);
```

### Error Handling
When validation fails, this module will default to returning a HTTP 400 with
the Joi validation error as a `text/plain` response type.

A `passError` option is supported to override this behaviour. This option
forces the middleware to pass the error to the express error handler using the
standard `next` function behaviour.

See the [Custom Express Error Handler](#custom-express-error-handler) section
for an example.

### Joi Options
It is possible to pass specific Joi options to each validator like so:

```js
route.get(
  '/tickets',
  validator.headers(
    headerSchema,
    {
      joi: {convert: true, allowUnknown: true}
    }
  ),
  validator.body(
    bodySchema,
    {
      joi: {convert: true, allowUnknown: false}
    }
  )
  routeHandler
);
```

The following sensible defaults for Joi are applied if none are passed:

#### Query
* convert: true
* allowUnknown: false
* abortEarly: false

#### Body
* convert: true
* allowUnknown: false
* abortEarly: false

#### Headers
* convert: true
* allowUnknown: true
* stripUnknown: false
* abortEarly: false

#### Route Params
* convert: true
* allowUnknown: false
* abortEarly: false

#### Fields (with express-formidable)
* convert: true
* allowUnknown: false
* abortEarly: false


## Custom Express Error Handler

```js
const validator = require('express-joi-validation').createValidator({
  // This options forces validation to pass any errors the express
  // error handler instead of generating a 400 error
  passError: true
});

const app = require('express')();
const orders = require('lib/orders');

app.get('/orders', validator.query(require('./query-schema')), (req, res, next) => {
  // if we're in here then the query was valid!
  orders.getForQuery(req.query)
    .then((listOfOrders) => res.json(listOfOrders))
    .catch(next);
});

// After your routes add a standard express error handler. This will be passed the Joi
// error, plus an extra "type" field so we can tell what type of validation failed
app.use((err, req, res, next) => {
  if (err && err.error && err.error.isJoi) {
    // we had a joi error, let's return a custom 400 json response
    res.status(400).json({
      type: err.type, // will be "query" here, but could be "headers", "body", or "params"
      message: err.error.toString()
    });
  } else {
    // pass on to another error handler
    next(err);
  }
});
```

In TypeScript environments `err.type` can be verified against the exported
`ContainerTypes`:

```ts
import { ContainerTypes } from 'express-joi-validation'

app.use((err: any|ExpressJoiError, req: express.Request, res: express.Response, next: express.NextFunction) => {
  // ContainerTypes is an enum exported by this module. It contains strings
  // such as "body", "headers", "query"...
  if (err && 'type' in err && err.type in ContainerTypes) {
    const e: ExpressJoiError = err
    // e.g "You submitted a bad query paramater"
    res.status(400).end(`You submitted a bad ${e.type} paramater`)
  } else {
    res.status(500).end('internal server error')
  }
})
```

---
_Source: https://npm.io/package/express-joi-validation · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
