next.jsreact-hook-formzod

How to handle file uploads with react-hook-form and zod in Next.js when passing file data to a use server function?


I'm working on a Next.js project using react-hook-form for form handling and zod for validation, specifically with a file input. The form validation is working fine, and I'm able to select a file successfully. Here's the relevant part of my form:

<FormField
  control={form.control}
  name="file"
  render={({ field }) => (
    <FormItem>
      <FormLabel>Beleg:</FormLabel>
      <FormControl>
        <Input
          accept="application/pdf"
          type="file"
          onChange={(e) =>
            field.onChange(e.target.files ? e.target.files[0] : null)
          }
        />
      </FormControl>
      <FormMessage />
    </FormItem>
  )}
/>

For validation, I'm using zod as follows:

file: z.instanceof(File),

My issue arises when I try to pass this file data to a use server function upon form submission. I get the following error

Error: Only plain objects, and a few built-ins, can be passed to Server Actions. Classes or null prototypes are not supported.

on

  async function onSubmit(values: z.infer<typeof validation>) {
    const formData = new FormData();

    // Append form fields to FormData
    Object.entries(values).forEach(([key, value]) => {
      formData.append(key, value as string);
    });
    
    await addFile(formData)



'use server'

async function addFile(data: z.infer<typeof validation>): Promise<xxxx> {
  const response = await handleApiFetch({
    url: url,
    method: 'POST',
    body: data,
  })
}

My Questions:


Solution

  • async function addFile(formData: FormData): Promise<xxxx> {
      // Parse the FormData using Zod
      const result = validation.safeParse(Object.fromEntries(formData));
    
      if (!result.success) {
        // Handle validation errors
        console.error(result.error);
        throw new Error('Validation failed');
      }
    
      const validatedData = result.data;
    
      // Now you can use the validated data
      const response = await handleApiFetch({
        url: url,
        method: 'POST',
        body: formData, // Use the original FormData for the API call
      });
      
     }