Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: hello-nrfcloud/lambda-helpers
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v2.1.0
Choose a base ref
...
head repository: hello-nrfcloud/lambda-helpers
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v2.1.1
Choose a head ref
  • 1 commit
  • 2 files changed
  • 1 contributor

Commits on Mar 3, 2025

  1. fix(validateResponse): handle responses created with aResponse

    coderbyheart committed Mar 3, 2025
    Copy the full SHA
    297f3ad View commit details
Showing with 45 additions and 12 deletions.
  1. +26 −6 src/validateResponse.spec.ts
  2. +19 −6 src/validateResponse.ts
32 changes: 26 additions & 6 deletions src/validateResponse.spec.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,48 @@
import { HttpStatusCode } from '@hello.nrfcloud.com/proto/hello'
import middy from '@middy/core'
import { Type } from '@sinclair/typebox'
import type { Context } from 'aws-lambda'
import assert from 'node:assert'
import { describe, it } from 'node:test'
import { aResponse } from './aResponse.js'
import {
ResponseValidationFailedError,
validateResponse,
} from './validateResponse.js'

void describe('validateResponse()', () => {
void it('should validate the response', async () =>
assert.equal(
assert.deepEqual(
await middy()
.use(validateResponse(Type.Boolean({ title: 'A boolean' })))
.handler(async () => true)('Some event', {} as Context),
true,
.use(validateResponse(Type.Object({ value: Type.Boolean() })))
.handler(async () =>
aResponse(HttpStatusCode.OK, {
'@context': new URL('https://example.com'),
value: true,
}),
)('Some event', {} as Context),
{
body: '{"@context":"https://example.com/","value":true}',
headers: {
'Cache-Control': 'public, max-age=60',
'content-length': '48',
'content-type': 'application/json',
},
statusCode: 200,
},
))

void it('should throw an Error in case the response is invalid', async () =>
assert.rejects(
async () =>
middy()
.use(validateResponse(Type.Boolean()))
.handler(async () => 42)('Some event', {} as Context),
.use(validateResponse(Type.Object({ value: Type.Boolean() })))
.handler(async () =>
aResponse(HttpStatusCode.OK, {
'@context': new URL('https://example.com'),
value: 42,
}),
)('Some event', {} as Context),
ResponseValidationFailedError,
))
})
25 changes: 19 additions & 6 deletions src/validateResponse.ts
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@ import {
import type middy from '@middy/core'
import type { TSchema } from '@sinclair/typebox'
import type { ValueError } from '@sinclair/typebox/errors'
import { tryAsJSON } from './tryAsJSON.js'
import { ValidationFailedError } from './validateInput.js'

export class ResponseValidationFailedError extends ValidationFailedError {
@@ -14,25 +15,37 @@ export class ResponseValidationFailedError extends ValidationFailedError {
}
}

/**
* Validate responses created with `aResponse`
*/
export const validateResponse = <ResponseSchema extends TSchema>(
schema: ResponseSchema,
): middy.MiddlewareObj => {
const validator = validateWithTypeBox(schema)
return {
after: async (req) => {
const maybeValid = validator(req.response)
const body = req.response?.body
if ((body?.length ?? 0) === 0) {
console.debug(`[validateResponse]`, `Response body is empty`)
}
if (
(req.response.headers['content-type']?.includes('application/json') ??
false) === false
) {
console.debug(`[validateResponse]`, `Response body is not JSON`)
}
const maybeValid = validator(tryAsJSON(req.response.body))
if ('errors' in maybeValid) {
console.error(
`[validateResponse]`,
`Response validation failed`,
JSON.stringify({
response: req.response,
errors: formatTypeBoxErrors(maybeValid.errors),
}),
req.response.body,
formatTypeBoxErrors(maybeValid.errors),
schema.title,
)
throw new ResponseValidationFailedError(maybeValid.errors)
}
console.debug(`[validateResponse]`, `Response is`, schema.title)
console.debug(`[validateResponse]`, `Response is valid`, schema.title)
return undefined
},
}