Skip to content

Commit

Permalink
remove comlexity, use safeParse instead
Browse files Browse the repository at this point in the history
  • Loading branch information
inkognitro committed Sep 25, 2024
1 parent b1ad08e commit 769d6a8
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 42 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ This implementation is responsible for validating the request and response data
This one is only available when Zod schemas are generated due to the `withZod: true` configuration.
This request handler does throw an error when requests or responses do not comply with the
zod schema definitions which are defined inside the requests' `endpointSchema` property.
It uses the [parse](https://zod.dev/?id=parse) method for this task.
It uses the [safeParse](https://zod.dev/?id=safeparse) method for this task.

## Promises: `resolve` vs `reject`
The provided `RequestHandler` implementations distinguish between "expected" and
Expand Down
91 changes: 50 additions & 41 deletions src/templates/ts/core/zodValidationRequestHandler.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {Request, RequestHandler, RequestResult, ResponseSchema} from './core';
import {z, ZodSchema} from 'zod';

export type ZodValidationRequestHandlerExecutionConfig = {};

Expand All @@ -12,76 +13,84 @@ export class ZodValidationRequestHandler implements RequestHandler {
this.cancelAllRequests = this.cancelAllRequests.bind(this);
}

private validateRequest(request: Request) {
public execute(
request: Request,
config?: ZodValidationRequestHandlerExecutionConfig
): Promise<RequestResult> {
return new Promise((resolve, reject) => {
const requestZodSchema = this.createRequestZodSchema(request);
const requestValidationResult = requestZodSchema.safeParse(request);
if (requestValidationResult.success) {
reject(requestValidationResult.error);
return;
}
this.nextRequestHandler.execute(request, config).then(rr => {
const requestZodSchema = this.createResponseZodSchema(rr);
const responseValidationResult = requestZodSchema.safeParse(
rr.response
);
if (!responseValidationResult.success) {
reject(responseValidationResult.error);
return;
}
resolve(rr);
});
});
}

private createRequestZodSchema(request: Request): ZodSchema {
const schemaProps: Record<string, ZodSchema> = {};
const schema = request.endpointSchema;
if (schema.pathParamsZodSchema) {
schema.pathParamsZodSchema.parse(request.pathParams);
schemaProps['pathParams'] = schema.pathParamsZodSchema;
}
if (schema.headersZodSchema) {
schema.headersZodSchema.parse(request.headers);
schemaProps['headers'] = schema.headersZodSchema;
}
if (schema.queryParamsZodSchema) {
schema.queryParamsZodSchema.parse(request.queryParams);
schemaProps['queryParams'] = schema.queryParamsZodSchema;
}
if (schema.cookiesZodSchema && request.cookies) {
schema.cookiesZodSchema.parse(request.cookies);
schemaProps['cookies'] = schema.cookiesZodSchema;
}
const contentType = request.contentType;
if (!contentType) {
return;
return z.object(schemaProps);
}
const bodySchema = schema.bodyByContentType[contentType];
if (!bodySchema || request.body instanceof FormData) {
return;
if (bodySchema && !(request.body instanceof FormData)) {
schemaProps['body'] = bodySchema.zodSchema;
}
bodySchema.zodSchema.parse(request.body);
return z.object(schemaProps);
}

private validateResponse(rr: RequestResult) {
private createResponseZodSchema(rr: RequestResult): ZodSchema {
const response = rr.response;
if (!response) {
return;
return z.object({});
}
const schemaByStatus = rr.request.endpointSchema.responseByStatus;
if (!schemaByStatus) {
return z.object({});
}
const schema: undefined | ResponseSchema =
rr.request.endpointSchema.responseByStatus?.[response.status];
schemaByStatus[response.status] ?? schemaByStatus['default'];
if (!schema) {
return;
return z.object({});
}
const schemaProps: Record<string, ZodSchema> = {};
if (schema.headersZodSchema) {
schema.headersZodSchema.parse(response.headers);
schemaProps['headers'] = schema.headersZodSchema;
}
const contentType = response.contentType;
if (!contentType) {
return;
return z.object(schemaProps);
}
const bodySchema = schema.bodyByContentType[contentType];
if (!bodySchema || response.body instanceof FormData) {
return;
if (bodySchema && !(response.body instanceof FormData)) {
schemaProps['body'] = bodySchema.zodSchema;
}
bodySchema.zodSchema.parse(response.body);
}

public execute(
request: Request,
config?: ZodValidationRequestHandlerExecutionConfig
): Promise<RequestResult> {
return new Promise((resolve, reject) => {
try {
this.validateRequest(request);
this.nextRequestHandler.execute(request, config).then(rr => {
try {
this.validateResponse(rr);
resolve(rr);
} catch (e) {
reject(e);
return;
}
});
} catch (e) {
reject(e);
return;
}
});
return z.object(schemaProps);
}

public cancelAllRequests() {
Expand Down

0 comments on commit 769d6a8

Please sign in to comment.