npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

koa-joiful-validation

v1.1.0

Published

Simple, opinionated request validation middleware for koa-router.

Downloads

5

Readme

npm Coveralls Travis CI Dependency Status devDependency Status peerDependency Status node License

koa-joiful-validation

Simple, opinionated request validation middleware for koa-router.

This module currently supports Koa 1 only.

Example

const Joi = require('joi');
const router = require('koa-router')();
const validate = require('koa-joiful-validation');

router.get('/posts', validate({
    query: {
        offset: Joi.number().integer().positive().default(0).optional()
        limit: Joi.number().integer().positive().default(100).optional()
    },
    body: { /* ... */ },   // for the request body
    params: { /* ... */ }, // for route parameters
}), function* () {
    // your code here
    this.request.query // contains the original, unmodified query
    this.state.query   // the modified query with defaults applied, etc.
});

Why is the result assigned to this.state?

Koa's request wrapper object automatically serializes all values assigned to its query property. This means that its values can not actually be coerced to other types, e.g. to numbers or booleans. To resolve this the modified data (conversions and defaults applied) are assigned to this.state.body, this.state.query and this.state.params instead.

Installation

Install as usual:

npm install --save koa-joiful-validation

Please note that this module has Joi as a peer dependency (practically any version will do).

In order for the request body validation to work correctly you will want to use koa-bodyparser.

Opinions

This module is quite opinionated. If it doesn't suit your needs, feel free to open an issue, create a pull request or just fork the project. In particular, keep the following things in mind:

  • If a validation fails, so does the request with a 422 Unprocessable Entity error.
  • All parameters are required by default (presence: 'required').
  • Additional parameters, i.e. parameters not specified in the schemas, are forbidden by default.
  • When no schema is given, the empty schema is assumed. This means that router.post('/', validate(), ...) will not accept any query, body or url parameters.
  • By default, query and url parameters are converted (e.g., cast to numbers as necessary), but body parameters are not.

Details

Route Parameters

If you have route parameters, you need to add them to your validation config in order to work:

router.get('/entity/:id', validate(), function* () {
    // this won't work because params.id will be rejected
});

So instead, do it like this:

router.get('/entity/:id', validate({
    params: {
        id: Joi.number().integer().min(1)
    }
}), function* () {
    // now this.state.params.id is guaranteed to be a positive integer
});

If you do not want to actually validate the parameter, simply use Joi.any().

Custom validation functions

You can pass a list of custom validation functions as a second parameter:

router.get('/equalsTen', validate({
    x: Joi.number(),
    y: Joi.number()
}, [
    function () {
        // 'this' is the regular koa context
        const { x, y } = this.state.params;
        if (x + y !== 10) {
            // Joi already converted the parameters from strings to numbers
            return 'x plus y must equal ten!';
        }
    }
]), function* () {
    // ...
});

These functions are run in sequence after the schema validations (and only if those succeed). If a function returns a string, that validation is considered to have failed and the string becomes the error message. Any other return value is interpreted as a success.

The functions are executed in the same context as the middleware itself so you have access to this.request, this.state etc.

If your validation is asynchronous, simply use a generator:

router.get('/:id', validate({
    params: { id: Joi.number() }
}, [
    function* () {
        const entity = yield this.db.findOne(this.state.params.id);
        return entity.isSpecial ? 'too special!' : entity;
    }
]), function* () {
    // ...
});

Please note that throwing an error from a validation function will abort the request with a 500 Internal Server Error.

Auto-wrapping

The values given in the configuration object are automatically passed to Joi.object().keys() if they are not already Joi schemas. In other words, the following two statements are equivalent:

validate({ query: { x: Joi.number() } });
validate({ query: Joi.object().keys({ x: Joi.number() }) });