Validating requests

A great way to ensure that we always get the data that we need is to validate requests before persisting them to the database. Mongoose already does schema validation, but we can also implement an extra layer of validation, to ensure that we are in full control of our data.

A popular JSON schema validation library that we can make use of in Node.js is Joi. Joi is an object schema validator, and it will work well for ensuring that we have the proper data coming through from our requests.

We will create a custom middleware for validating requests on selected routes, and register it in our app.

First, let's create the middleware function. Creating a validator.js file in the middleware folder can be done by using the following command:

touch middleware/validator.js

Now, we can insert the following content into the file:

// ./middleware/validator.js

const Joi = require('joi');

const schema = Joi.object({
name: Joi.string().required(),
address: Joi.string(),
company: Joi.string(),
position: Joi.string(),
phoneNumber: Joi.number().required()
});

const ALLOWED_METHODS = ['PUT', 'POST'];

module.exports = () => {
return async (ctx, next) => {
const { method } = ctx;
const { body } = ctx.request;

if (ALLOWED_METHODS.includes(method)) {
const { error } = Joi.validate(body, schema);
if (error) {
ctx.status = 422;
ctx.body = {
status: 'error',
message: 'validation error',
errors: error.details.map(e => e.message)
};
} else {
await next();
}
} else {
await next();
}
};
};

In the preceding code block, we specify the methods that we would like to validate against in the ALLOWED_METHODS variable. This ensures that we only validate against POST and PUT requests that contain request body data, and not GET requests, which do not. If a request matches any of these methods, we then validate the request body against a defined schema.

Joi possesses various methods for schema validation. Notably, we make use of the .required() method, to ensure that the name and phoneNumber properties are always present.

Note that we only specify one validation schema in our application, as we only have one data model. In more complex applications, which possess multiple data models, multiple schemas need to be implemented, where the correct schema to use for validation can be decided based on the route.

If an error occurs from Joi during validation, we set the response status code to 422 (Unprocessable Entity) and send back the error messages from Joi.

To register the middleware, let's update the index.js file, as follows:

// ./index.js
// ...

const validator = require('./middleware/validator');

app.use(validator());

// ...

At this point, the complete index.js file looks as follows:

const Koa = require('koa');
const logger = require('koa-logger');
const bodyParser = require('koa-body');
const router = require('./middleware/router');
const validator = require('./middleware/validator');
const app = new Koa();

const mongoose = require('mongoose');
mongoose.connect(
'mongodb://localhost:27017/koa-contact',
{ useNewUrlParser: true }
);

const db = mongoose.connection;
db.on('error', error => {
throw new Error(`error connecting to db: ${error}`);
});
db.once('open', () => console.log('database connected'));

app.use(logger());

app.use(bodyParser());

app.use(validator());

app.use(router.routes());
app.use(router.allowedMethods());

const port = process.env.PORT || 3000;
app.listen(port, () =>
console.log(`Server running on http://localhost:${port}`)
);

If we try to save a contact without specifying a name, the following is an example response that we might receive:

{
"status": "error",
"message": "validation error",
"errors": [
""name" is required"
]
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.196.217