Quantcast
Channel: Stories by Tal Bereznitskey on Medium
Viewing all articles
Browse latest Browse all 20

Keeping your Lambda functions safe with Joi

$
0
0

We’re big fans of Serverless functions at Torii, and we’re always looking for ways to increase the robustness and our productivity.

Photo that has nothing to do with Lambda fucnctions by Matthew M

One of the problems we face with Lambda functions is making sure invocations are passed the correct inputs. As we’re also (happy) users of Hapi and Joi, we decided to borrow the input validation idea and apply it to our Lambda functions.

Example validation

Here’s a simple Lambda function that calculates a full name based on first and last names:

export const handler = async (e, context) => {
const { firstName, lastName } = e
return [firstName, lastName].filter(Boolean).join(' ')
}

We’d like to make sure that firstName and lastName are always sent in the event e and that those are valid strings.

In order to validate the input with Joi, we’ve written a utility function to wrap our handler, handlerWrapper and this is how we use it:

import Joi from '@hapi/joi'
import { handlerWrapper } from './handlerWrapper'
export const handler = handlerWrapper({
validation: {
e: {
firstName: Joi.string().min(3).max(20).required(),
lastName: Joi.string().min(3).max(20).required()
}
},
handler: async (e, context) => {
const { firstName, lastName } = e
return [firstName, lastName].filter(Boolean).join(' ')
}
})

We pass the handlerWrapper two arguments:

  • The validation schema, powered by Joi
  • The Lambda handler, which is the same as before

The event e will be validated based on the Joi schema provided and will throw an exception if it did not pass validation. Keeping your function safe and exposing invalid invocations.

Testing

Let’s invoke the function using the Serverless Framework with some valid and invalid inputs:

serverless invoke -f fullname --data '{ "firstName": "Steve" }'
// Throws an exception
// Error: "lastName" is required

And another:

serverless invoke -f fullname --data '{ "firstName": "St", lastName: "Jobs" }'
// Throws an exception
// Error "firstName" length must be at least 3 characters long

And a valid input:

serverless invoke -f fullname --data '{ "firstName": "Steve", lastName: "Jobs" }'
RESULT:
"Steve Jobs"

The code

This is the code for handlerwrapper.js:

import Joi from '@hapi/joi'

export const handlerWrapper = (options) => {
const { validate = {}, handler } = validateAndThrow(options, schema)

return async (e, ctx) => {
const eventWithDefaults = validateAndThrow(e, validate.e || {})
return handler(eventWithDefaults, ctx)
}
}

const validateAndThrow = (e, schema) => {
const { result, isValid, errors } = validateEvent(e, schema)
if (!isValid) {
throw new Error(errors.join(', '))
}

return result
}

const validateEvent = (e, schema) => {
const result = Joi.validate(e, schema)
const isValid = (result.error === null)
const errors = isValid ? null : result.error.details.map(detail => detail.message)

return { result: result.value, isValid, errors }
}

const schema = {
validate: Joi.object({
e: Joi.object()
})
,
handler: Joi.func().maxArity(2)
}

Other ideas?

If you have other ideas for making Lambda functions more robust, please share with me in the comments or over twitter at ketacode.


Keeping your Lambda functions safe with Joi was originally published in The Startup on Medium, where people are continuing the conversation by highlighting and responding to this story.


Viewing all articles
Browse latest Browse all 20

Latest Images

Trending Articles





Latest Images