Search code examples
next.jsformidablesanity

What's the proper way for returning a response using Formidable on Nextjs Api?


I'm sending an uploaded file to a Next.js API route using FormData. The file is then processed on the API route using formidable and passed to sanity client in order to upload the asset, but I can't return the data to the client... I get this message in console:

API resolved without sending a response for /api/posts/uploadImage, this may result in stalled requests.

When console logging the document inside the API everything is in there, I just can't send back that response to client side. Here's my client upload function:

const addPostImage = (e) => {
    const selectedFile = e.target.files[0];

    if (
      selectedFile.type === "image/jpeg" ||
      selectedFile.type === "image/png" ||
      selectedFile.type === "image/svg" ||
      selectedFile.type === "image/gif" ||
      selectedFile.type === "image/tiff"
    ) {
      const form = new FormData();
      form.append("uploadedFile", selectedFile);
      axios
        .post("/api/posts/uploadImage", form, {
          headers: { "Content-Type": "multipart/form-data" },
        })
        .then((image) => {
          setPostImage(image);
          toast.success("Image uploaded!");
        })
        .catch((error) => {
          toast.error(`Error uploading image ${error.message}`);
        });
    } else {
      setWrongImageType(true);
    }
  };

This is my API:

import { client } from "../../../client/client";
import formidable from "formidable";
import { createReadStream } from "fs";

export const config = {
  api: {
    bodyParser: false,
  },
};

export default async (req, res) => {
  const form = new formidable.IncomingForm();
  form.keepExtensions = true;
  form.parse(req, async (err, fields, files) => {
    const file = files.uploadedFile;
    const document = await client.assets.upload(
      "image",
      createReadStream(file.filepath),
      {
        contentType: file.mimetype,
        filename: file.originalFilename,
      }
    );
    console.log(document);
    res.status(200).json(document);
  });
};

Solution

  • Solution:

    As stated in the comments by @juliomalves, I had to promisify the form parsing function and await its results like so:

    import { client } from "../../../client/client";
    import formidable from "formidable";
    import { createReadStream } from "fs";
    
    export const config = {
      api: {
        bodyParser: false,
      },
    };
    
    export default async (req, res) => {
      const form = new formidable.IncomingForm();
    
      form.keepExtensions = true;
    
      const formPromise = await new Promise((resolve, reject) => {
        form.parse(req, async (err, fields, files) => {
          if (err) reject(err);
          const file = files.uploadedFile;
          const document = await client.assets.upload(
            "image",
            createReadStream(file.filepath),
            {
              contentType: file.mimetype,
              filename: file.originalFilename,
            }
          );
          resolve(document);
        });
      });
    
      res.json(formPromise);
    }; 
    

    Then I checked for the response's status on the client-side.