Express.js simple json validation


If you ever wrote an application using express, you surely have faced the problem of how to handle the request body validation.

In brief, I'll show you how I validate incoming JSON data in a very simple way.

First, install tiinvo

Secondly, create both a typeguard and a factory for your incoming data type.

import { Str, Obj } from 'tiinvo';

export interface User {
  username: string;
  password: string;
}

export type t = User;

//#region typeguards

export const guard = Obj.guardOf<t>({
  username: Str.guard,
  password: Str.guard,
})

//#endregion

//#region factories

export const make = (partial: Partial<t> = {}): t => ({
  username: partial.username ?? ``,
  password: partial.password ?? ``,
})

//#endregion

Thirdly, create a validation middleware for express.js

import type { Handler } from 'express';
import { Str, Predicate, pipe, Functors } from 'tiinvo';

const ispostmethod = pipe(Str.lowercase, Predicate.eq(`post`))
const ispatchmethod = pipe(Str.lowercase, Predicate.eq(`patch`))
const ismethodallowed = Predicate.or(ispostmethod, ispatchmethod)

export const guardBody = <t>(
  guard: Functors.guard<t>, 
  typename: string,
): Handler => {
  return (req, res, next) => {
    if (!ismethodallowed(req.method)) {
      return res.status(406).json({ error: `method not acceptable` })
    }

    if (guard(req.body)) {
      return next();
    } else {
      return res.status(400).json({ error: `not a valid ${typename}` })
    }
  }
}

Then use the middleware for each route you need to guard

import { Router } from 'express';
import { guardBody } from './guard-body';
import * as User from './User.ts';

export const user = Router();

const userBody = guardBody(User.guard, 'User');

user.post('/user', userBody, (req, res) => {
  const usr = User.make(req.body);
  res.status(200).json({ hello: usr.username })
});

If you try to call that endpoint with a valid User type, it will respond properly.

Also, you made data validation a breeze.

Other blog entries