fets
Version:
TypeScript HTTP Framework focusing on e2e type-safety, easy setup, performance & great developer experience
89 lines (88 loc) • 4.37 kB
JavaScript
import { getHeadersObj } from '@whatwg-node/server';
import { Response } from '../Response.js';
import { isZodSchema } from './types.js';
export function useZod() {
return {
onRoute({ schemas, handlers }) {
if (schemas) {
const validationMiddlewares = new Map();
const requestSchemas = schemas.request;
if (requestSchemas) {
if (isZodSchema(requestSchemas.headers)) {
const headersSchema = requestSchemas.headers;
validationMiddlewares.set('headers', request => {
const headersObj = getHeadersObj(request.headers);
const result = headersSchema.safeParse(headersObj);
if (!result.success) {
return result.error.issues;
}
return [];
});
}
if (isZodSchema(requestSchemas.params)) {
const paramsSchema = requestSchemas.params;
validationMiddlewares.set('params', request => {
const result = paramsSchema.safeParse(request.params);
if (!result.success) {
return result.error.issues;
}
return [];
});
}
if (isZodSchema(requestSchemas.query)) {
const querySchema = requestSchemas.query;
validationMiddlewares.set('query', request => {
const result = querySchema.safeParse(request.query);
if (!result.success) {
return result.error.issues;
}
return [];
});
}
if (isZodSchema(requestSchemas.json)) {
const jsonSchema = requestSchemas.json;
validationMiddlewares.set('json', async (request) => {
const contentType = request.headers.get('content-type');
if (contentType?.includes('json')) {
const jsonObj = await request.json();
Object.defineProperty(request, 'json', {
value: async () => jsonObj,
configurable: true,
});
const result = jsonSchema.safeParse(jsonObj);
if (!result.success) {
return result.error.issues;
}
}
return [];
});
}
if (validationMiddlewares.size > 0) {
handlers.unshift(async (request) => {
const validationErrorsNonFlat = await Promise.all([...validationMiddlewares.entries()].map(async ([name, fn]) => {
const errors = await fn(request);
if (errors.length > 0) {
return errors.map(error => ({
name,
...error,
}));
}
}));
const validationErrors = validationErrorsNonFlat.flat().filter(Boolean);
if (validationErrors.length > 0) {
return Response.json({
errors: validationErrors,
}, {
status: 400,
headers: {
'x-error-type': 'validation',
},
});
}
});
}
}
}
},
};
}