formidable

repository·master·Indexed 27 days ago

https://github.com/node-formidable/formidable

A high-performance Node.js module for parsing form data, specifically optimized for handling multipart/form-data file uploads. It supports integration with the built-in Node.js http module, Express.js, and Koa. Version 3.5.4 provides features such as custom upload directories, file size limits, checksum calculation via hashAlgorithm, and a plugin system via .use().

Tokens
7.6K
Snippets
13
Records
34
Agent score
91%

What's inside formidable

  1. Use v2 of formidable

    master

    Version v2 is available for users who cannot yet move to v3. It requires Node.js version 10 or higher. It features modernized code, better organization, and improved documentation compared to v1.

    To ensure stability, it is recommended to lock your installation to the v2-latest dist-tag:

    npm install formidable@v2-latest
  2. Install formidable

    master

    Install formidable using npm or yarn. This project requires Node.js >= 10.13.

    Depending on the version you need, use the following commands:

    • For v2: npm install formidable@v2
    • For v3: npm install formidable@v3
    • For the latest version (v2 currently): npm install formidable
    # v2
    npm install formidable
    npm install formidable@v2
    
    # v3
    npm install formidable@v3
  3. Upgrade from v1 to v2 or v3

    master

    Version v1 is deprecated and no longer maintained. It does not receive bugfixes, security fixes, or new features. It is highly recommended to migrate to at least v2 or preferably v3.

    To upgrade to v2, install using:

    npm install formidable@v2

    If you encounter issues with v2, it is recommended to move to v3.

  4. Use v3 of formidable

    master

    Version v3 (available via formidable@latest) is the recommended version. It is rewritten as an ESModule and uses a monorepo structure with more plugins and helper utilities. It utilizes modern Node.js Streams and includes various optimizations.

    Requirements and Compatibility:

    • Requires Node.js version 12-14 or higher.
    • Uses ESModules.
    • Does not maintain compatibility with v1 APIs.
  5. Filter uploaded files

    master

    You can provide a filter function in the options object to decide which files should be uploaded. The function receives an object containing { name, originalFilename, mimetype } and must return a boolean. If it returns false, the file is not uploaded.

    const options = {
      filter: function ({ name, originalFilename, mimetype }) {
        // keep only images
        return mimetype && mimetype.includes("image");
      },
    };
  6. Configure Formidable upload options

    master

    The options object controls how files and fields are processed. Key options include:

    • encoding (string): Encoding for incoming form fields (default: 'utf-8').
    • uploadDir (string): Directory for file uploads (default: os.tmpdir()).
    • keepExtensions (boolean): Include original file extensions (default: false).
    • allowEmptyFiles (boolean): Allow uploading empty files (default: false).
    • minFileSize (number): Minimum size of uploaded file in bytes (default: 1).
    • maxFiles (number): Limit number of uploaded files (default: Infinity).
    • maxFileSize (number): Limit size of each uploaded file in bytes (default: 200 * 1024 * 1024).
    • maxTotalFileSize (number): Limit total size of all uploaded files (default: options.maxFileSize).
    • maxFields (number): Limit number of fields (default: 1000).
    • maxFieldsSize (number): Limit total memory for all fields in bytes (default: 20 * 1024 * 1024).
    • hashAlgorithm (string | false): Include checksums for files (e.g., 'sha1', 'md5').
    • fileWriteStreamHandler (function): Custom function returning a Writable stream to redirect uploads (e.g., to AWS S3 or Azure Blob Storage). This disables default local filesystem writing.
    • filename (function): Function (name, ext, part, form) -> string to control the new filename. It will be joined with uploadDir.
    • filter (function): Function ({name, originalFilename, mimetype}) -> boolean to filter files before upload. Returning false ignores the file.
    • createDirsFromUploads (boolean): If true, allows direct folder uploads (requires uploadDir and a filename function that returns paths with /).
    • enabledPlugins (array): List of plugins to enable (e.g., [octetstream, querystring, json]).
  7. Use formidable with Node.js http module

    master

    You can parse file uploads using the built-in Node.js http module. Create a formidable instance and call form.parse(req, callback) where req is the incoming message stream. The callback provides err, fields, and files.

    import http from "node:http";
    import formidable, { errors as formidableErrors } from "formidable";
    
    const server = http.createServer((req, res) => {
      if (req.url === "/api/upload" && req.method.toLowerCase() === "post") {
        // parse a file upload
        const form = formidable({});
    
        form.parse(req, (err, fields, files) => {
          if (err) {
            // example to check a very specific error
            if (err.code === formidableErrors.maxFieldsExceeded) {
            }
            res.writeHead(err.httpCode || 400, { "Content-Type": "text/plain" });
            res.end(String(err));
            return;
          }
          res.writeHead(200, { "Content-Type": "application/json" });
          res.end(JSON.stringify({ fields, files }, null, 2));
        });
    
        return;
      }
    
      // show a file upload form
      res.writeHead(200, { "Content-Type": "text/html" });
      res.end(`
        <h2 with Node.js <code"http" module</h2>
        <form action="/api/upload" enctype="multipart/form-data" method="post">
          <div Text field title: <input type="text" name="title" /></div>
          <div File: <input type="file" name="multipleFiles" multiple="multiple" /></div>
          <input type="submit" value="Upload" />
        </form>
      `);
    });
    
    server.listen(8080, () => {
      console.log("Server listening on http://localhost:8080/ ...");
    });
  8. Parse file uploads with Express.js

    master

    Formidable can be used within Express.js by passing the Node.js Request stream (req) to form.parse. This can be done without additional middleware.

    import express from "express";
    import formidable from "formidable";
    
    const app = express();
    
    app.get("/", (req, res) => {
      res.send(`
        <h2 with <code"express" npm package></h2>
        <form action="/api/upload" enctype="multipart/form-data" method="post">
          <div>Text field title: <input type="text" name="title" /></div
          <div>File: <input type="file" name="someExpressFiles" multiple="multiple" /></div
          <input type="submit" value="Upload" />
        </form>
      `);
    });
    
    app.post("/api/upload", (req, res, next) => {
      const form = formidable({});
    
      form.parse(req, (err, fields, files) => {
        if (err) {
          next(err);
          return;
        }
        res.json({ fields, files });
      });
    });
    
    app.listen(3000, () => {
      console.log("Server listening on http://localhost:3000 ...");
    });
  9. Use formidable with Express.js

    master

    Since formidable only requires the Node.js Request stream, you can use it within an Express route without third-party middleware. Pass the req object directly to form.parse().

    import express from "express";
    import formidable from "formidable";
    
    const app = express();
    
    app.get("/", (req, res) => {
      res.send(`
        <h2 With <code"express" npm package</h2>
        <form action="/api/upload" enctype="multipart/form-data" method="post">
          <div Text field title: <input type="text" name="title" /></div>
          <div File: <input type="file" name="someExpressFiles" multiple="multiple" /></div>
          <input type="submit" value="Upload" />
        </form>
      `);
    });
    
    app.post("/api/upload", (req, res, next) => {
      const form = formidable({});
    
      form.parse(req, (err, fields, files) => {
        if (err) {
          next(err);
          return;
        }
        res.json({ fields, files });
      });
    });
    
    app.listen(3000, () => {
      console.log("Server listening on http://localhost:3000 ...");
    });
  10. Parse file uploads with Node.js http module

    master

    You can use Formidable to parse incoming multipart/form-data requests using the built-in Node.js http module. The form.parse(req) method can be awaited to return an array containing [fields, files].

    import http from "node:http";
    import formidable, { errors as formidableErrors } from "formidable";
    
    const server = http.createServer(async (req, res) => {
      if (req.url === "/api/upload" && req.method.toLowerCase() === "post") {
        // parse a file upload
        const form = formidable({});
        let fields;
        let files;
        try {
          [fields, files] = await form.parse(req);
        } catch (err) {
          // example to check for a very specific error
          if (err.code === formidableErrors.maxFieldsExceeded) {
          }
          console.error(err);
          res.writeHead(err.httpCode || 400, { "Content-Type": "text/plain" });
          res.end(String(err));
          return;
        }
        res.writeHead(200, { "Content-Type": "application/json" });
        res.end(JSON.stringify({ fields, files }, null, 2));
        return;
      }
    
      // show a file upload form
      res.writeHead(200, { "Content-Type": "text/html" });
      res.end(`
        <h2 with Node.js <code"http" module</h2>
        <form action="/api/upload" enctype="multipart/form-data" method="post">
          <div>Text field title: <input type="text" name="title" /></div
          <div>File: <input type="file" name="multipleFiles" multiple="multiple" /></div
          <input type="submit" value="Upload" />
        </form>
      `);
    });
    
    server.listen(8080, () => {
      console.log("Server listening on http://localhost:8080/ ...");
    });
  11. Parse file uploads with Koa

    master

    When using Koa, you must pass ctx.req (the Node.js Request object) to form.parse, not ctx.request (the Koa Request object).

    import Koa from "Koa";
    import formidable from "formidable";
    
    const app = new Koa();
    
    app.on("error", (err) => {
      console.error("server error", err);
    });
    
    app.use(async (ctx, next) => {
      if (ctx.url === "/api/upload" && ctx.method.toLowerCase() === "post") {
        const form = formidable({});
    
        // not very elegant, but that's for now if you don't want to use `koa-better-body`
        // or other middlewares.
        await new Promise((resolve, reject) => {
          form.parse(ctx.req, (err, fields, files) => {
            if (err) {
              reject(err);
              return;
            }
    
            ctx.set("Content-Type", "application/json");
            ctx.status = 200;
            ctx.state = { fields, files };
            ctx.body = JSON.stringify(ctx.state, null, 2);
            resolve();
          });
        });
        await next();
        return;
      }
    
      // show a file upload form
      ctx.set("Content-Type", "text/html");
      ctx.status = 200;
      ctx.body = `
        <h2 with <code"koa" npm package></h2>
        <form action="/api/upload" enctype="multipart/form-data" method="post">
          <div>Text field title: <input type="text" name="title" /></div
          <div>File: <input type="file" name="koaFiles" multiple="multiple" /></div
          <input type="submit" value="Upload" />
        </form>
      `;
    });
    
    app.use((ctx) => {
      console.log("The next middleware is called");
      console.log("Results:", ctx.state);
    });
    
    app.listen(3000, () => {
      console.log("Server listening on http://localhost:3000 ...");
    });
  12. Use formidable with Koa

    master

    When using Koa, you must pass ctx.req (the Node.js request) to form.parse(), NOT ctx.request (the Koa request object). You can wrap the form.parse callback in a Promise to use it within async/await middleware.

    import Koa from "Koa";
    import formidable from "formidable";
    
    const app = new Koa();
    
    app.on("error", (err) => {
      console.error("server error", err);
    });
    
    app.use(async (ctx, next) => {
      if (ctx.url === "/api/upload" && ctx.method.toLowerCase() === "post") {
        const form = formidable({});
    
        // not very elegant, but for now if you don't want to use `koa-better-body`
        // or other middlewares.
        await new Promise((resolve, reject) => {
          form.parse(ctx.req, (err, fields, files) => {
            if (err) {
              reject(err);
              return;
            }
    
            ctx.set("Content-Type", "application/json");
            ctx.status = 200;
            ctx.state = { fields, files };
            ctx.body = JSON.stringify(ctx.state, null, 2);
            resolve();
          });
        });
        await next();
        return;
      }
    
      // show a file upload form
      ctx.set("Content-Type", "text/html");
      ctx.status = 200;
      ctx.body = `
        <h2 With <code"koa" npm package</h2>
        <form action="/api/upload" enctype="multipart/form-data" method="post">
          <div Text field title: <input type="text" name="title" /></div>
          <div File: <input type="file" name="koaFiles" multiple="multiple" /></div>
          <input type="submit" value="Upload" />
        </form>
      `;
    });
    
    app.use((ctx) => {
      console.log("The next middleware is called");
      console.log("Results:", ctx.state);
    });
    
    app.listen(3000, () => {
      console.log("Server listening on http://localhost:3000 ...");
    });