Skip to content

Commit 443202b

Browse files
feat(validation): Add Middy.js middleware for JSON Schema validation (#3694)
Co-authored-by: Andrea Amorosi <[email protected]>
1 parent 34d917e commit 443202b

File tree

2 files changed

+112
-0
lines changed

2 files changed

+112
-0
lines changed

Diff for: packages/validation/src/middleware.ts

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { SchemaValidationError } from './errors.js';
2+
import type { ValidatorOptions } from './types.js';
3+
import { validate } from './validate.js';
4+
5+
export function validation(options: ValidatorOptions) {
6+
return {
7+
before: async (handler: { event: unknown }) => {
8+
if (options.inboundSchema) {
9+
try {
10+
handler.event = validate({
11+
payload: handler.event,
12+
schema: options.inboundSchema,
13+
envelope: options.envelope,
14+
formats: options.formats,
15+
externalRefs: options.externalRefs,
16+
ajv: options.ajv,
17+
});
18+
} catch (error) {
19+
throw new SchemaValidationError('Inbound validation failed', error);
20+
}
21+
}
22+
},
23+
after: async (handler: { response: unknown }) => {
24+
if (options.outboundSchema) {
25+
try {
26+
handler.response = validate({
27+
payload: handler.response,
28+
schema: options.outboundSchema,
29+
formats: options.formats,
30+
externalRefs: options.externalRefs,
31+
ajv: options.ajv,
32+
});
33+
} catch (error) {
34+
throw new SchemaValidationError('Outbound validation failed', error);
35+
}
36+
}
37+
},
38+
};
39+
}

Diff for: packages/validation/tests/unit/middleware.test.ts

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import middy from '@middy/core';
2+
import { describe, expect, it } from 'vitest';
3+
import { SchemaValidationError } from '../../src/errors.js';
4+
import { validation } from '../../src/middleware.js';
5+
6+
const inboundSchema = {
7+
type: 'object',
8+
properties: {
9+
inputValue: { type: 'number' },
10+
},
11+
required: ['inputValue'],
12+
additionalProperties: false,
13+
};
14+
15+
const outboundSchema = {
16+
type: 'object',
17+
properties: {
18+
outputValue: { type: 'number' },
19+
},
20+
required: ['outputValue'],
21+
additionalProperties: false,
22+
};
23+
24+
const response = { outputValue: 20 };
25+
const baseHandler = async (event: unknown) => {
26+
return response;
27+
};
28+
29+
describe('validation middleware with Middy', () => {
30+
it('should validate inbound and outbound successfully', async () => {
31+
// Prepare
32+
const middleware = validation({ inboundSchema, outboundSchema });
33+
const wrappedHandler = middy(baseHandler).use(middleware);
34+
const event = { inputValue: 10 };
35+
// Act
36+
const result = await wrappedHandler(event);
37+
// Assess
38+
expect(result).toEqual(response);
39+
});
40+
41+
it('should throw error on inbound validation failure', async () => {
42+
// Prepare
43+
const middleware = validation({ inboundSchema });
44+
const wrappedHandler = middy(baseHandler).use(middleware);
45+
const invalidEvent = { inputValue: 'invalid' };
46+
// Act & Assess
47+
await expect(wrappedHandler(invalidEvent)).rejects.toThrow(
48+
SchemaValidationError
49+
);
50+
});
51+
52+
it('should throw error on outbound validation failure', async () => {
53+
const invalidHandler = async (_event: unknown) => {
54+
return { outputValue: 'invalid' };
55+
};
56+
const middleware = validation({ outboundSchema });
57+
const wrappedHandler = middy(invalidHandler).use(middleware);
58+
const event = { any: 'value' };
59+
// Act & Assess
60+
await expect(wrappedHandler(event)).rejects.toThrow(SchemaValidationError);
61+
});
62+
63+
it('should no-op when no schemas are provided', async () => {
64+
// Prepare
65+
const middleware = validation({});
66+
const wrappedHandler = middy(baseHandler).use(middleware);
67+
const event = { anyKey: 'anyValue' };
68+
// Act
69+
const result = await wrappedHandler(event);
70+
// Assess
71+
expect(result).toEqual(response);
72+
});
73+
});

0 commit comments

Comments
 (0)