Skip to content

[question] How to save a file using formData? #207

@pruge

Description

@pruge

I tried to save the file as follows:
Next.js + tRPC + FormData

I am unable to proceed further as I am getting the following error:

TRPCClientError: [
  {
    "code": "invalid_type",
    "expected": "string",
    "received": "undefined",
    "path": [
      "category"
    ],
    "message": "Required"
  },
  {
    "code": "invalid_type",
    "expected": "string",
    "received": "undefined",
    "path": [
      "project"
    ],
    "message": "Required"
  },
  {
    "code": "custom",
    "message": "Input not instance of File",
    "fatal": true,
    "path": [
      "file"
    ]
  }
]
    at y.from (renderer.mjs:135:21)
    at Object.next (renderer.mjs:529:23)
    at ne.v (renderer.mjs:512:21)
    at eval (renderer.mjs:490:21)

Is there an example of how to save the file?

I tried the following:
api.ts

export const UploadFileSchema = zfd.formData({
  category: zfd.text(),
  project: zfd.text(),
  file: zfd.file(),
})
export const GetFileSchema = z.object({
  category: z.string(),
  project: z.string(),
})

export const router = t.router({
  getFiles: t.procedure.input(GetFileSchema).query(async (req) => {
    const { input } = req
    const { category, project } = input
    const filelist = await getFilelist(category, project)
    const assets = await Promise.all(
      filelist.map(async (file) => {
        const type = await getType(file.cwd, file.name)
        // console.log('type', type, file)
        return {
          category: type,
          type,
          src: file.url,
        }
      }),
    )

    return assets as unknown as Asset[]
  }),
  uploadFile: t.procedure.input(UploadFileSchema).mutation(async (req) => {
    console.log('uploadHmiFile', req)
    // const { input } = req
    // const { category, project, file } = input

    // const { cwd, url, name } = await writeFileToDisk(category, project, file)

    // const type = await getType(cwd, name)
    // return {
    //   category,
    //   type,
    //   src: url,
    // }
  }),
})

uploader.tsx

const upload = trpc.uploadFile.useMutation({
    onSuccess() {
      alert('success!')
    },
    onError(err) {
      console.log(err)
    },
  })

  const onDrop = useCallback((acceptedFiles) => {
    try {
      const file = acceptedFiles[0]
      const formData = new FormData()
      formData.append('category', 'hmi')
      formData.append('project', 'test')
      formData.append('file', file)

      for (const pair of formData.entries()) {
        console.log(pair[0] + ', ' + pair[1])
      }

      const dataObject = UploadFileSchema.parse(formData)
      console.log(formData, dataObject)

      upload.mutate(formData)
    } catch (error) {
      console.log(error)
    }
  }, [])
  const { getRootProps, getInputProps } = useDropzone({ onDrop })

console.log, error

category, hmi
project, test
file, [object File]

 FormData {} {category: 'hmi', project: 'test', file: File}

TRPCClientError: [
  {
    "code": "invalid_type",
    "expected": "string",
    "received": "undefined",
    "path": [
      "category"
    ],
    "message": "Required"
  },
  {
    "code": "invalid_type",
    "expected": "string",
    "received": "undefined",
    "path": [
      "project"
    ],
    "message": "Required"
  },
  {
    "code": "custom",
    "message": "Input not instance of File",
    "fatal": true,
    "path": [
      "file"
    ]
  }
]
    at y.from (renderer.mjs:135:21)
    at Object.next (renderer.mjs:529:23)
    at ne.v (renderer.mjs:512:21)
    at eval (renderer.mjs:490:21)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions