API Parameters Validation

I wonder if anyone uses some library to validate API calls parameters. So far we use Vandium (https://github.com/vandium-io/vandium-node) but it seems that it does not work with lambda-proxy integration which we need.

When some parameter is wrong, it ends the lambda function with similar output:

{
    "errorMessage": "validation error: Parameter email is required and should have format of email address",
    "errorType": "Error",
    "stackTrace": []
}

And APIG fails with internal error because it must get output like { "statusCode": 400, "body": "..." }.

Vandium encapsulates code of the lambda function so validation error can’t be simply caught and transformed in it. The code looks like:

module.exports.appsDetail = vandium.createInstance({
  validation: {
    schema: {
      headers: vandium.types.object().keys({
        Authorization: vandium.types.string().required(),
      }),
      pathParameters: vandium.types.object().keys({
        appId: vandium.types.string().required(),
        version: vandium.types.number().integer(),
      }),
    },
  },
}).handler((event, context, callback) => {
  ...

I’ve been using Validator to handle simple validation.

https://www.npmjs.com/package/validator

I’m using Joi https://github.com/hapijs/joi

something like this:

const Joi = require('joi');
// const {customResponse, customError} = require('responses');

const validation = {
  post: {
    body: Joi.object().keys({
      name: Joi.string().min(1).max(128).required(),
    })
  },
};

const controller = {
  post(event, context, done) {
    MyModel
      .put({
        name: event.parsedData.name,
      })
      .then(response => done(null, customResponse(response)))
      .catch(err => done(null, customError(err)));
  },
};


// Export validated functions only
Object.keys(validation).forEach(methodName => {
  const validationObj = validation[methodName];
  const controllerFn = controller[methodName];
  if (validationObj && controllerFn) {
    module.exports[methodName] = validate(validationObj, controllerFn);
  }
});


function validate(validation, fn) {
  let proxy = fn;

  if (validation.body) {
    proxy = paramsValidation(proxy, 'body', validation.body);
  }

  if (validation.queryStringParameters) {
    proxy = paramsValidation(proxy, 'queryStringParameters', validation.queryStringParameters);
  }

  return proxy;
}

function paramsValidation(fn, field, schema) {
  return function(event, context, done) {
    const raw = event[field];
    const params = raw ? JSON.parse(event[field]) : {};

    Joi.validate(params, schema, (err, value) => {
      if (err) {
        const firstMessage = ((err.details || [])[0] || {}).message;
        return done(null, customError({
          errorMessage: firstMessage || err.details,
          errorType: 'InvalidParametersException',
          statusCode: 400,
        }));
      } else {
        event.parsedData = Object.assign({}, value, event.parsedData);
        fn(event, context, done);
      }
    });
  };
};

Ah, it looks good. Vandium internally uses Joi so migration could be quite easy. Thank you guys.