How can I get progress of file uploading from uploader.upload_stream and pass it to api

I'm developing nextjs app with api routes, I have a route to upload file to cloudinary localhost/api/files/upload. There I send files with axios and receive axios uploadProgressEvent to display it on web page. I see that progress works fine when I upload file to api route, at 100% upload I need to wait more because file is streamed with  uploader.upload_stream to cloudinary. How can I pass progress from uploader.upload_stream to axios uploadProgress event with through my api? So the uploadProgressEvent shows uploading to api route and from api route to cloudinary?

Api route

export async function POST(req: NextRequest) {
  try {
    const formData = await req.formData();
    const formDataEntryValues = Array.from(formData.values());
    for (const formDataEntryValue of formDataEntryValues) {
      if (typeof formDataEntryValue === "object" && "arrayBuffer" in formDataEntryValue) {
        const file = formDataEntryValue as unknown as Blob;


        if (file.size > config.maxFileSize) {
          return BadRequest(`Max file size is ${config.maxFileSizeAsString}`);
        }


        const buffer = Buffer.from(await file.arrayBuffer());
        const response = await uploadWrapper(buffer);


        return NextResponse.json(response, { status: 200 });
      }
    }
  } catch (error: any) {
    return NextResponse.json(error, { status: 500 });
  }
}


const uploadWrapper = async (buffer: Buffer) => {
  return new Promise(async (resolve, reject) => {
    const cloud_upload_stream = await cloudinary.v2.uploader.upload_stream({
      folder: config.storePath
    }, (error, result) => {
      if (error) {
        reject(error);
      } else {
        resolve(result);
      }
    });
    streamifier.createReadStream(buffer).pipe(cloud_upload_stream);
  })
}

OnUploadingProgressChange

const onUploadProgressChange = (id: string) => (event: AxiosProgressEvent) => {
    if (event && event.loaded && event.total) {
      const uploadingFile = uploadedFilesRef.current.find((f: UploadedFileType) => f.id === id);
      if (uploadingFile) {
        const newProgress = Math.round((100 * event.loaded) / event.total);
        const updatedFile: UploadedFileType = {
          ...uploadingFile,
          progress: newProgress
        };
        setUploadedFiles(uploadedFilesRef.current.map((f) => f.id === id ? updatedFile : f));
      }
    }
  }

Function to upload file to api

export async function upload(file: File, onUploadProgress: (e: AxiosProgressEvent) => void) {
  try {
    const formData = new FormData();
    formData.append("file", file);


    const response = await axios.post("/api/files/upload", formData, {
      headers: {
        'Content-Type': 'multipart/form-data'
      },
      onUploadProgress: onUploadProgress
    })


    return response.data;
  } catch (error: any) {
    throw new Error(`Failed to upload a file: ${error.response.data.message}`);
  }


}


Comments

  • Tamara
    Tamara Member, Cloudinary Staff Posts: 123

    Hi there,

    Thanks for reaching out! Unfortunately, since the cloudinary.v2.uploader.upload_stream method doesn't provide a direct progress event like axios does, it's not possible to directly sync the progress from your API route to Cloudinary. There might be a custom solution you can implement yourself.

    Kind regards,

    Tamara