@novice1/validator-json - v0.1.9
    Preparing search index...

    @novice1/validator-json - v0.1.9

    @novice1/validator-json

    JSON schema validator to use with @novice1/routing.

    It provides a middleware that can validate req.params, req.body, req.query, req.headers, req.cookies and req.files against a schema using Ajv.

    npm install @novice1/validator-json
    
    // router.ts

    import routing from '@novice1/routing'
    import { validatorJson } from '@novice1/validator-json'

    export default const router = routing()

    /**
    * Enable JSON validation on:
    * - req.params
    * - req.body
    * - req.query
    * - req.headers
    * - req.cookies
    * - req.files
    *
    * for that router
    */
    router.setValidators(
    validatorJson(
    // ajv options
    { allErrors: true, keywords: ['meta', 'discriminator'] },
    // middleware in case validation fails
    function onerror(err, req, res, next) {
    res.status(400).json(err)
    }
    )
    )

    Typescript interfaces are optional but convenient as they can help defining the JSON schema and be used in the controller.

    import express from 'express'
    import { JSONSchemaType } from 'ajv'
    import router from './router'

    // interface for "req.body"
    interface BodyItem {
    name: string
    }

    // JSON schema for "req.body"
    const bodySchema: JSONSchemaType<BodyItem> = {
    type: 'object',
    properties: {
    name: {
    type: 'string',
    minLength: 1
    }
    },
    required: ['name'],
    additionalProperties: false
    }

    router.post(
    {
    name: 'Post item',
    path: '/items',

    // the schema to validate
    parameters: {
    type: 'object',
    properties: {
    body: bodySchema
    },
    required: ['body'],
    additionalProperties: true
    },

    // body parser
    preValidators: express.json()
    },
    function (req: routing.Request<unknown, { name: string }, BodyItem>, res) {
    res.json({ name: req.body.name })
    }
    )

    // interface for "req.query"
    interface GetQuery {
    version?: string
    }

    // JSON schema for "req.query"
    const querySchema: JSONSchemaType<GetQuery> = {
    type: 'object',
    properties: {
    version: {
    type: 'string',
    description: 'version number',
    enum: ['1','2','3'],
    default: '2',
    examples: ['2'],
    nullable: true
    }
    }
    }

    router.get(
    {
    name: 'Main app',
    path: '/app',
    parameters: {
    // the schema to validate
    query: querySchema
    }
    },
    function (req, res) {
    res.send(req.query.version)
    }
    )
    import express from 'express'
    import { Type, Static } from '@sinclair/typebox'
    import routing from '@novice1/routing'
    import router from './router'

    // schema for "req.body"
    const bodySchema = Type.Object({
    name: Type.String()
    })

    // type for "req.body"
    type BodyItem = Static<typeof bodySchema>

    router.post(
    {
    name: 'Post item',
    path: '/items',

    // the schema to validate
    parameters: Type.Object({
    body: bodySchema
    }),

    // body parser
    preValidators: express.json()
    },
    function (req: routing.Request<unknown, { name: string }, BodyItem>, res) {
    res.json({ name: req.body.name })
    }
    )

    // schema for "req.query"
    const querySchema = Type.Object({
    version: Type.Optional(
    Type.Union([
    Type.Literal('1'),
    Type.Literal('2'),
    Type.Literal('3')
    ], {
    type: 'string',
    default: '2',
    description: 'version number',
    examples: ['2']
    })
    )
    })

    // type for "req.query"
    type GetQuery = Static<typeof querySchema>

    router.get(
    {
    name: 'Main app',
    path: '/app',
    parameters: {
    // the schema to validate
    query: querySchema
    }
    },
    function (req: routing.Request<unknown, string, unknown, GetQuery>, res) {
    res.send(req.query.version)
    }
    )
    import express from 'express'
    import { S } from 'fluent-json-schema'
    import routing from '@novice1/routing'
    import router from './router'

    router.post(
    {
    name: 'Post item',
    path: '/items',

    parameters: S.object()
    .prop('body', S.object().prop('name', S.string().required().minLength(1)))
    .required()
    .valueOf(),

    // body parser
    preValidators: express.json()
    },
    function (req, res) {
    res.json({ name: req.body.name })
    }
    )

    router.get(
    {
    name: 'Main app',
    path: '/app',
    parameters: {
    query: S.object()
    .prop(
    'version',
    S.string()
    .description('version number')
    .maxLength(1)
    .enum(['1', '2', '3'])
    .default('2')
    .examples(['2'])
    )
    .valueOf()
    }
    },
    function (req, res) {
    res.send(req.query.version)
    }
    )

    Override the validator's options and the error handler for a route.

    import routing from '@novice1/routing'
    import { validatorJson } from '@novice1/validator-json'
    import Logger from '@novice1/logger'
    import { Options } from 'ajv'

    const router = routing()

    router.setValidators(
    validatorJson(
    // default options
    { allErrors: true, keywords: ['meta', 'discriminator'] },
    // default error handler
    function onerror(err, req, res, next) {
    res.status(400).json(err)
    }
    )
    )

    const onerror: routing.ErrorRequestHandler = (err, req, res) => {
    res.status(400).json(err)
    }

    const validatorJsonOptions: Options = { logger: Logger, allErrors: false }

    router.get(
    {
    path: '/override',
    parameters: {
    // overrides
    onerror,
    validatorJsonOptions

    },
    },
    function (req, res) {
    // ...
    }
    )

    To keep your schemas "isolated" from other properties of parameters, you should define one property that will contain those schemas.

    To do that you just need to initiate the validator with the name of the property:

    router.setValidators(
    validatorJson(
    // ajv options
    {},
    // middleware in case validation fails
    undefined,
    // name of the property in 'parameters'
    'schema'
    )
    )

    Then in your routes you can do:

    router.get(
    {
    name: 'Main app',
    path: '/app',
    // parameters
    parameters: {
    // property 'schema'
    schema: {
    query: {
    type: 'object',
    properties: {
    version: {
    type: 'string',
    description: 'version number',
    enum: ['1','2','3'],
    default: '2',
    examples: ['2'],
    nullable: true
    }
    }
    }
    }
    }
    },
    function (req, res) {
    res.json(req.query.version)
    }
    )