Validating REST endpoints with JSON Schemas using Express and Node.js

Input validation is important. In this post we take a look at how we can use JSON Schemas to validate our input values for our REST endpoints. I have used the example of an online market where you can submit items for sale. The implementation is done using Express and Node.js.

I use the express, jsonschema and body-parser packages for Node.js in this example. Express allows us to easily create our server, JSONSchema’s Validator class is used to validate our client request input and body-parser is a tool to help us get a JSON representation of our request's body.

To install the previously mentioned packages simply run the following commands and you are ready to go.

npm install express body-parser jsonschema

Declaring the JSON Schema

The item for sale would have fields containing information about the seller as well as the properties of the item itself. We declare the following two schemas. Notice that the itemSchema object holds a reference to our userSchema object and that all mandatory properties are defined as required.

var userSchema = { "id":"/User", "type":"object", "properties":{  "username": {"type":"string"},  "email": {   "type": "string",   "format" : "email"  },  "votes": {"type": "integer"} }, "required" :["username","email","votes"]};var itemSchema = { "id":"/Item", "type":"object", "properties": {  "price": {"type":"number"},  "width": {"type":"integer"},  "height": {"type":"integer"},  "added": {"type": "string",  "format": "date-time"},  "seller": {"$ref": "/User"},  "image": {   "type": "string",   "format": "uri"  } }, "required" :["price","width","height","added","seller"]};var validator = new jsonValidator();validator.addSchema(userSchema,"/User");

In order to instantiate our validator and link our two schemas we instantiate a new validator object and call addSchema as shown above.

Adding validation to our endpoint in Express

Validating our client request is fairly easy at this point, but we must check that our request contains the "Content-Type application/json" header and more importantly that we provide our validator with the option of throwing an error on an invalid comparison. With that said you can see validating our header and request body.

if(req.get("Content-Type")!="application/json") { res.status(401).send("Invalid header format"); return;}try { validator.validate(req.body,itemSchema, "throwError":true});} catch(error) { res.status(401).end("Invalid body format: " + error.message); return;}

Testing our Endpoint with Postman

I am using Postman to generate a valid and an invalid request as shown below.

no-alt

no-alt

Complete code example

var express = require('express');var jsonValidator = require('jsonschema').Validator;var bodyParser = require('body-parser');var app = express();app.use(bodyParser.urlencoded({ extended: false }));app.use(bodyParser.json());var userSchema = {  id: '/User',  type: 'object',  properties: {    username: { type: 'string' },    email: {      type: 'string',      format: 'email'    },    votes: { type: 'integer' }  },  required: ['username', 'email', 'votes']};var itemSchema = {  id: '/Item',  type: 'object',  properties: {    price: { type: 'number' },    width: { type: 'integer' },    height: { type: 'integer' },    added: {      type: 'string',      format: 'date-time'    },    seller: { $ref: '/User' },    image: {      type: 'string',      format: 'uri'    }  },  required: ['price', 'width', 'height', 'added', 'seller']};var validator = new jsonValidator();validator.addSchema(userSchema, '/User');app.post('/validate', function(req, res) {  if (req.get('Content-Type') != 'application/json') {    res.status(401).send('Invalid header format');    return;  }  try {    validator.validate(req.body, itemSchema, { throwError: true });  } catch (error) {    res.status(401).end('Invalid body format: ' + error.message);    return;  }  res.status(200).send('Valid request format');});app.listen(8000, function() {  console.log('Validation app listening on port 8000');});