Response body validation using middy

288 Views Asked by At

This is the return statement of my lambda function:

  return {
    statusCode: 201,
    body: JSON.stringify({item: 'apple', price: 1}),
  }

How can I use middy to validate that the body is an object with properties: item and price?

The body should always be returned as a string (JSON.stringify) otherwise the lambda function fails on runtime.

Therefore schema validation here fails (I skipped checking for item and price properties for now):

const responseSchema = transpileSchema({
  type: 'object',
  required: ['body', 'statusCode'],
  properties: {
    body: {
      type: 'object'
    },
    statusCode: {
      type: 'number'
    }
  }
})

But this works nonetheless:

const responseSchema = transpileSchema({
  type: 'object',
  required: ['body', 'statusCode'],
  properties: {
    body: {
      type: 'string'
    },
    statusCode: {
      type: 'number'
    }
  }
})

This is my middleware sequence

import middy from '@middy/core'
import cors from '@middy/http-cors'
import globalErrorHandler from './globalErrorHandler.js'
import httpJsonBodyParser from '@middy/http-json-body-parser'
import validator from '@middy/validator'

    return middy()
    .use(cors())
    .use(httpJsonBodyParser())
    .use(validator({ eventSchema }))
    .use(validator({ responseSchema }))
    .use(globalErrorHandler())
    .handler(handler)
const globalErrorHandler = () => {
    const onError = async (request) => {
        const { error } = request;
        return {
            statusCode: error.statusCode|| 500,
            body: JSON.stringify({ error:{...error, cause: error.cause} }),
        };
    }
    return { onError };
}

export default globalErrorHandler;
1

There are 1 best solutions below

0
On BEST ANSWER

I resolved by issue by using the http-response-serializer from middy. Upon lambda JSON response (not string), the validator will validate the response body and then the middy http-response-serializer middleware serializes the lambda response.

The validator did not seem to serialize the response under the hood.

Lambda function

  return {
    statusCode: 201,
    body: Object({item:{...params.Item}}),
  }

Middleware

middy()
        .use(cors())
        .use(httpResponseSerializer({
            serializers: [
                {
                    regex: /^application\/xml$/,
                    serializer: ({ body }) => `<message>${body}</message>`
                },
                {
                    regex: /^application\/json$/,
                    serializer: ({ body }) => JSON.stringify(body)
                },
                {
                    regex: /^text\/plain$/,
                    serializer: ({ body }) => body
                }
            ],
            defaultContentType: 'application/json'
        }))
        .use(validator({responseSchema}))
        .handler(handler)