Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/evanshortiss/express-joi-validation
validate express application inputs and parameters using joi
https://github.com/evanshortiss/express-joi-validation
express express-middleware express-validation joi middleware typescript
Last synced: 3 days ago
JSON representation
validate express application inputs and parameters using joi
- Host: GitHub
- URL: https://github.com/evanshortiss/express-joi-validation
- Owner: evanshortiss
- License: mit
- Created: 2017-04-13T00:09:14.000Z (almost 8 years ago)
- Default Branch: master
- Last Pushed: 2024-12-13T07:47:00.000Z (about 1 month ago)
- Last Synced: 2025-01-12T23:00:58.376Z (10 days ago)
- Topics: express, express-middleware, express-validation, joi, middleware, typescript
- Language: JavaScript
- Homepage:
- Size: 84 KB
- Stars: 99
- Watchers: 5
- Forks: 21
- Open Issues: 8
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
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, 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// Without Joi.extractType you would do this:
// query: {
// name: string
// }
}app.get(
'/hello',
validator.query(querySchema),
(req: ValidatedRequest, 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 && 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')
}
})
```