Skip to content

Instantly share code, notes, and snippets.

@aparx
Last active February 21, 2023 08:02
Show Gist options
  • Save aparx/98d942779c0b326d9493e7d89649b023 to your computer and use it in GitHub Desktop.
Save aparx/98d942779c0b326d9493e7d89649b023 to your computer and use it in GitHub Desktop.
Little gist providing two functions to parse a form from an incoming message and also validate it immediately using a given Zod schema.
import formidable from 'formidable';
import { IncomingMessage } from 'http';
import { z, ZodObject, ZodType } from 'zod';
export type KnownFormFields = Record<string, ZodType>;
export type FormParseResult<TFields, TFiles> = {
error?: Error;
fields?: TFields;
files?: TFiles;
};
export async function parseIncomingForm<TFields = any, TFiles = any>(
request: IncomingMessage
): Promise<FormParseResult<TFields, TFiles>> {
return await new Promise((resolve, reject) => {
formidable().parse(request, (error: any, fields: any, files: any) => {
if (error) reject({ error });
resolve({ error, fields, files });
});
});
}
/**
* Parses the form fields potentially given in the request using given schema
* and throws an error if the fields do not match the expectations.
*
* @example
* const { name } = validateIncomingFields(request, z.object({ name: z.string() }));
*
* @param request - the incoming message (often the to be handled API request)
* @param schema - the schema used to parse given request's form data
*/
export async function validateIncomingFields<
TFields extends KnownFormFields,
TObject extends ZodObject<TFields>
>(request: IncomingMessage, schema: TObject): Promise<z.infer<TObject>> {
const data = await parseIncomingForm<TFields>(request);
if (!data.error) return schema.parse(data.fields);
return Promise.reject(data.error);
}
@aparx
Copy link
Author

aparx commented Feb 17, 2023

  "dependencies": {
    "@types/formidable": "^2.0.5",
    "formidable": "^2.1.1",
    "typescript": "4.9.5",
    "zod": "^3.20.6"
  }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment