Skip to content

Commit

Permalink
Add types to ZodContext.invalid
Browse files Browse the repository at this point in the history
  • Loading branch information
tomaskallup committed May 7, 2024
1 parent 4af4ef7 commit baa69b8
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 22 deletions.
14 changes: 7 additions & 7 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ export type Method =
| 'unlock'
| 'unsubscribe';

export interface ZodRouterInvalid {
body?: ZodError;
headers?: ZodError;
params?: ZodError;
query?: ZodError;
files?: ZodError;
export interface ZodRouterInvalid<Headers, Params, Query, Body, Files> {
body?: ZodError<Body>;
headers?: ZodError<Headers>;
params?: ZodError<Params>;
query?: ZodError<Query>;
files?: ZodError<Files>;
error?: boolean;
}

Expand All @@ -63,7 +63,7 @@ export interface ZodContext<Headers, Params, Query, Body, Files> extends Context
query: Query;
files: Files;
} & Request;
invalid: ZodRouterInvalid;
invalid: ZodRouterInvalid<Headers, Params, Query, Body, Files>;
}

export type ValidationOptions<Headers, Params, Query, Body, Files, Response> = {
Expand Down
34 changes: 19 additions & 15 deletions src/validation-middleware.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { DefaultContext, Next } from 'koa';
import { ZodError, ZodTypeAny } from 'zod';
import { ValidationOptions, RouterOpts, ZodRouterInvalid, ZodValidationError } from './types';
import { ValidationOptions, RouterOpts, ZodValidationError, ZodRouterInvalid } from './types';
import { assertValidation, assertZodValidationError, noopMiddleware } from './util';

class ValidationError extends Error {
Expand All @@ -23,7 +23,7 @@ const validate = async <T>(
return {
requestParameter,
error: parsed.error,
};
} as ZodValidationError<T>;
}

return parsed.data;
Expand All @@ -47,19 +47,23 @@ export const validationMiddleware = <H, P, Q, B, F, R>(

return async (ctx: DefaultContext, next: Next) => {
const validated = await Promise.all([
validate(ctx.request.headers, validation.headers, 'headers'),
validate(ctx.request.params, validation.params, 'params'),
validate(ctx.request.query, validation.query, 'query'),
validate(ctx.request.body, validation.body, 'body'),
validate(ctx.request.files, validation.files, 'files'),
validate<H>(ctx.request.headers, validation.headers, 'headers'),
validate<P>(ctx.request.params, validation.params, 'params'),
validate<Q>(ctx.request.query, validation.query, 'query'),
validate<B>(ctx.request.body, validation.body, 'body'),
validate<F>(ctx.request.files, validation.files, 'files'),
]);

const inputErrors = validated.reduce((acc: ZodRouterInvalid, curr) => {
if (assertZodValidationError(curr)) {
acc[curr.requestParameter] = curr.error;
}
return acc;
}, {});
const inputErrors = validated.reduce<ZodRouterInvalid<H, P, Q, B, F>>(
(acc, curr) => {
if (assertZodValidationError(curr)) {
(acc[curr.requestParameter] as typeof curr.error) = curr.error;
}

return acc;
},
{ error: false },
);

if (inputErrors.body || inputErrors.files || inputErrors.headers || inputErrors.params || inputErrors.query) {
if (validation?.continueOnError || opts?.validationErrorHandler) {
Expand Down Expand Up @@ -90,13 +94,13 @@ export const validationMiddleware = <H, P, Q, B, F, R>(

await next();

const output = await validate(ctx.body, validation.response, 'response');
const output = await validate<R>(ctx.body, validation.response, 'response');

if (!output) {
return;
}

if (output.error instanceof ZodError) {
if (assertZodValidationError<R>(output)) {
if (opts?.exposeResponseErrors) {
ctx.status = 500;
ctx.type = 'json';
Expand Down

0 comments on commit baa69b8

Please sign in to comment.