UNPKG

@athenna/http

Version:

The Athenna Http server. Built on top of fastify.

102 lines (101 loc) 3.47 kB
/** * @athenna/http * * (c) João Lenon <lenon@athenna.io> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ import { Is } from '@athenna/common'; import { ZodValidationException } from '#src/exceptions/ZodValidationException'; export function normalizeRouteSchema(options) { const request = {}; const response = {}; const schema = { ...options }; const swaggerSchema = { ...options }; const requestKeys = ['body', 'headers', 'params', 'querystring']; requestKeys.forEach(key => { if (!isZodSchema(options[key])) { return; } request[key] = options[key]; schema[key] = toJsonSchema(options[key], 'input'); swaggerSchema[key] = toJsonSchema(options[key], 'input'); }); if (options.response && Is.Object(options.response)) { schema.response = { ...options.response }; swaggerSchema.response = { ...options.response }; Object.entries(options.response).forEach(([statusCode, value]) => { if (!isZodSchema(value)) { return; } response[statusCode] = value; swaggerSchema.response[statusCode] = toJsonSchema(value, 'output'); delete schema.response[statusCode]; }); if (!Object.keys(schema.response).length) { delete schema.response; } } const hasZodSchemas = Object.keys(request).length > 0 || Object.keys(response).length > 0; return { schema, swaggerSchema, zod: hasZodSchemas ? { request, response } : null }; } export async function parseRequestWithZod(req, schemas) { const requestSchemas = schemas.request; if (requestSchemas.body) { req.body = await parseSchema(requestSchemas.body, req.body); } if (requestSchemas.headers) { req.headers = await parseSchema(requestSchemas.headers, req.headers); } if (requestSchemas.params) { req.params = await parseSchema(requestSchemas.params, req.params); } if (requestSchemas.querystring) { req.query = await parseSchema(requestSchemas.querystring, req.query); } } export async function parseResponseWithZod(reply, payload, schemas) { const schema = getResponseSchema(reply.statusCode, schemas.response); if (!schema) { return payload; } const result = await schema.safeParseAsync(payload); return result.success ? result.data : payload; } function getResponseSchema(statusCode, schemas) { return (schemas[statusCode] || schemas[String(statusCode)] || schemas[`${String(statusCode)[0]}xx`] || schemas.default || null); } async function parseSchema(schema, data) { const result = await schema.safeParseAsync(data); if (!result.success) { throw new ZodValidationException(result.error); } return result.data; } function toJsonSchema(schema, io) { const jsonSchemaMethod = schema['~standard']?.jsonSchema?.[io] || schema.toJSONSchema; if (!jsonSchemaMethod) { return {}; } const jsonSchema = jsonSchemaMethod({ target: 'draft-07', libraryOptions: { unrepresentable: 'any' } }); delete jsonSchema.$schema; return jsonSchema; } function isZodSchema(value) { return (Is.Defined(value) && Is.Function(value.parse) && Is.Function(value.safeParseAsync)); }