### Install Formidable v2 and v3 Source: https://github.com/node-formidable/formidable/blob/master/README.md Instructions for installing specific versions of the formidable package using npm. ```bash npm install formidable@v2 ``` ```bash npm install formidable npm install formidable@v3 ``` -------------------------------- ### Check Node.js Version Source: https://github.com/node-formidable/formidable/blob/master/benchmark/2022-11-30-i5-9600k.txt Verify the installed Node.js version. This is useful for ensuring compatibility and tracking performance differences across versions. ```bash node -v ``` -------------------------------- ### Parse Request with Formidable (Callback-based) Source: https://context7.com/node-formidable/formidable/llms.txt This is a commented-out example demonstrating the callback-based approach for parsing requests with Formidable. It's an alternative to the Promise-based method shown in the main example. ```javascript // const form2 = formidable({}); // form2.parse(req, (err, fields, files) => { // if (err) { next(err); return; } // res.json({ fields, files }); // }); ``` -------------------------------- ### Handle Formidable Events Source: https://github.com/node-formidable/formidable/blob/master/README.md Listen to various formidable events like 'fileBegin', 'file', and 'field' to process data as it arrives. This example emits custom 'data' events for centralized handling. ```javascript form.once("error", console.error); form.on("fileBegin", (formname, file) => { form.emit("data", { name: "fileBegin", formname, value: file }); }); form.on("file", (formname, file) => { form.emit("data", { name: "file", formname, value: file }); }); form.on("field", (fieldName, fieldValue) => { form.emit("data", { name: "field", key: fieldName, value: fieldValue }); }); form.once("end", () => { console.log("Done!"); }); // If you want to customize whatever you want... form.on( "data", ({ name, key, value, buffer, start, end, formname, ...more }) => { if (name === "partBegin") { } if (name === "partData") { } if (name === "headerField") { } if (name === "headerValue") { } if (name === "headerEnd") { } if (name === "headersEnd") { } if (name === "field") { console.log("field name:", key); console.log("field value:", value); } if (name === "file") { console.log("file:", formname, value); } if (name === "fileBegin") { console.log("fileBegin:", formname, value); } } ); ``` -------------------------------- ### Parse File Upload with Koa Source: https://github.com/node-formidable/formidable/blob/master/README.md This example demonstrates how to use Formidable with Koa. It requires passing `ctx.req` (Node.js's Request object) to `form.parse`. The snippet includes handling the upload and serving an HTML form. ```javascript 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 = `

With "koa" npm package

Text field title:
File:
`; }); 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 ..."); }); ``` -------------------------------- ### Parse Request with Callback Source: https://github.com/node-formidable/formidable/blob/master/README.md Use the `form.parse` method to process incoming request data. This example shows the callback-based approach, logging fields and files. ```javascript const form = formidable({ uploadDir: __dirname }); form.parse(req, (err, fields, files) => { console.log("fields:", fields); console.log("files:", files); }); ``` -------------------------------- ### Handle Specific Parts with onPart Source: https://github.com/node-formidable/formidable/blob/master/README.md Override the `onPart` method to selectively process incoming parts. This example shows how to let Formidable handle only non-file parts. ```javascript const form = formidable(); form.onPart = function (part) { // let formidable handle only non-file parts if (part.originalFilename === "" || !part.mimetype) { // used internally, please do not override! form._handlePart(part); } }; ``` -------------------------------- ### Parse File Upload with Express.js Source: https://github.com/node-formidable/formidable/blob/master/README.md Integrate Formidable with Express.js to handle file uploads. This example shows how to set up a route for serving an upload form and another for processing the uploaded files. ```javascript import express from "express"; import formidable from "formidable"; const app = express(); app.get("/", (req, res) => { res.send( `

With "express" npm package

Text field title:
File:
` ); }); 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 ..."); }); ``` -------------------------------- ### Intercept Raw Multipart Parts with onPart Source: https://context7.com/node-formidable/formidable/llms.txt Override `form.onPart` to manually handle specific multipart parts. Call `form._handlePart(part)` for parts that should be processed by Formidable normally. This example only lets Formidable handle text fields. ```javascript import http from 'node:http'; import formidable from 'formidable'; const server = http.createServer((req, res) => { const form = formidable(); // Only let Formidable handle text fields; handle files manually form.onPart = (part) => { if (!part.originalFilename && !part.mimetype) { // It's a text field — let formidable handle it normally form._handlePart(part); return; } // It's a file — handle it ourselves (e.g. discard or inspect) console.log(`Intercepted file part: ${part.originalFilename}`); part.on('data', (buffer) => { console.log(` chunk: ${buffer.length} bytes`); }); part.on('end', () => { console.log(` done: ${part.originalFilename}`); }); }; form.parse(req, (err, fields) => { if (err) { res.writeHead(400).end(err.message); return; } res.end(JSON.stringify({ fields })); }); }); server.listen(8080); ``` -------------------------------- ### Get First Values of Fields with Exceptions Source: https://github.com/node-formidable/formidable/blob/master/README.md The `firstValues` helper retrieves the first value for each field, similar to pre-3.0.0 behavior. It accepts an optional list of exceptions where arrays of strings should still be preserved, such as for multi-select inputs. ```javascript import { firstValues } from 'formidable/src/helpers/firstValues.js'; // ... form.parse(request, async (error, fieldsMultiple, files) => { if (error) { //... } const exceptions = ['thisshouldbeanarray']; const fieldsSingle = firstValues(form, fieldsMultiple, exceptions); // ... }); ``` -------------------------------- ### Initialize Formidable with Options Source: https://github.com/node-formidable/formidable/blob/master/README.md Instantiate the Formidable parser with custom options. Pass options to the constructor, not by assigning them to the instance. ```javascript import formidable from "formidable"; const form = formidable(options); ``` -------------------------------- ### Formidable Initialization Source: https://github.com/node-formidable/formidable/blob/master/README.md Instantiate Formidable with options to configure its behavior for parsing incoming form data and handling file uploads. ```APIDOC ## Formidable / IncomingForm All shown are equivalent. _Please pass [`options`](#options) to the function/constructor, not by assigning them to the instance `form`_ ```js import formidable from "formidable"; const form = formidable(options); ``` ``` -------------------------------- ### Event: 'fileBegin' Source: https://github.com/node-formidable/formidable/blob/master/README.md Emitted when a new file is detected. Useful for streaming files to alternative locations while Formidable buffers them. ```APIDOC ## Event: 'fileBegin' ### Description Emitted whenever a new file is detected in the upload stream. Use this event if you want to stream the file to somewhere else while buffering the upload on the file system. ### Parameters - **formName** (string) - The name of the form field or http filename for octetstream. - **file** (object) - An object containing file details: - **originalFilename** (string | null) - The original filename or null if there was a parsing error. - **newFilename** (string) - The generated filename (hexoid or from options.filename). - **filepath** (string) - The default path for saving the file, based on options.uploadDir and options.filename. This can be modified before the file is written. ### Example ```js form.on("fileBegin", (formName, file) => { // formName: the name in the form () or http filename for octetstream // file.originalFilename: http filename or null if there was a parsing error // file.newFilename: generated hexoid or what options.filename returned // file.filepath: default pathname as per options.uploadDir and options.filename // file.filepath = CUSTOM_PATH; // to change the final path }); ``` ``` -------------------------------- ### Formidable Options Configuration Source: https://context7.com/node-formidable/formidable/llms.txt Configure Formidable instance with various options for encoding, upload directories, file size limits, and more. All options are passed during instance creation. ```javascript import formidable from 'formidable'; // All available options with their defaults const form = formidable({ encoding: 'utf-8', // encoding for incoming form fields uploadDir: os.tmpdir(), // directory for file uploads keepExtensions: false, // preserve original file extensions allowEmptyFiles: false, // allow zero-byte file uploads minFileSize: 1, // minimum file size in bytes maxFiles: 1000, // maximum number of files per request maxFileSize: 200 * 1024 * 1024, // 200 MB per file maxTotalFileSize: undefined, // defaults to maxFileSize maxFields: 1000, // maximum number of non-file fields maxFieldsSize: 20 * 1024 * 1024,// 20 MB total for all fields hashAlgorithm: false, // e.g. 'sha256', 'md5' — false to disable fileWriteStreamHandler: null, // custom writable stream factory (for S3 etc.) createDirsFromUploads: false, // create subdirectories from uploaded folder structure filter: ({ name, originalFilename, mimetype }) => true, // return false to skip a file filename: undefined, // custom filename function (name, ext, part, form) => string }); ``` -------------------------------- ### Run Formidable Benchmark Source: https://github.com/node-formidable/formidable/blob/master/benchmark/2022-11-30-i5-9600k.txt Execute the benchmark script for the Formidable library. This command is used to measure performance. ```bash npm run bench ``` -------------------------------- ### Handle New File Uploads with formidable Source: https://github.com/node-formidable/formidable/blob/master/README.md Use the 'fileBegin' event to detect new file uploads. This is useful for streaming files to other locations while buffering them on the file system. You can access form name, original filename, generated filename, and filepath. ```javascript form.on("fileBegin", (formName, file) => { // accessible here // formName the name in the form () or http filename for octetstream // file.originalFilename http filename or null if there was a parsing error // file.newFilename generated hexoid or what options.filename returned // file.filepath default pathname as per options.uploadDir and options.filename // file.filepath = CUSTOM_PATH // to change the final path }); ``` -------------------------------- ### formidable(options) Source: https://context7.com/node-formidable/formidable/llms.txt Creates a new Formidable (IncomingForm) instance with the specified options. All configuration should be passed during instantiation. ```APIDOC ## formidable(options) — Create a form parser instance The default export is a factory function that returns a `Formidable` (also known as `IncomingForm`) instance. All configuration is passed as `options` to this factory; do not assign options to the instance after creation. The instance is an `EventEmitter` and supports both callback and Promise-based parsing. ```js import formidable from 'formidable'; // All available options with their defaults const form = formidable({ encoding: 'utf-8', // encoding for incoming form fields uploadDir: os.tmpdir(), // directory for file uploads keepExtensions: false, // preserve original file extensions allowEmptyFiles: false, // allow zero-byte file uploads minFileSize: 1, // minimum file size in bytes maxFiles: 1000, // maximum number of files per request maxFileSize: 200 * 1024 * 1024, // 200 MB per file maxTotalFileSize: undefined, // defaults to maxFileSize maxFields: 1000, // maximum number of non-file fields maxFieldsSize: 20 * 1024 * 1024,// 20 MB total for all fields hashAlgorithm: false, // e.g. 'sha256', 'md5' — false to disable fileWriteStreamHandler: null, // custom writable stream factory (for S3 etc.) createDirsFromUploads: false, // create subdirectories from uploaded folder structure filter: ({ name, originalFilename, mimetype }) => true, // return false to skip a file filename: undefined, // custom filename function (name, ext, part, form) => string }); ``` ``` -------------------------------- ### Handle Formidable Errors with Typed Error Codes Source: https://context7.com/node-formidable/formidable/llms.txt Use Formidable's typed error codes for precise error handling in asynchronous operations. This example demonstrates handling common errors like exceeding file size limits or too many fields. Ensure the server is listening on port 8080. ```javascript import formidable, { errors as formidableErrors } from 'formidable'; import http from 'node:http'; const server = http.createServer(async (req, res) => { const form = formidable({ maxFileSize: 1024 * 1024 }); // 1 MB limit try { const [fields, files] = await form.parse(req); res.end(JSON.stringify({ fields, files })); } catch (err) { // err.code matches a numeric constant from formidableErrors switch (err.code) { case formidableErrors.biggerThanMaxFileSize: // 1016 res.writeHead(413).end('File exceeds 1 MB limit'); break; case formidableErrors.biggerThanTotalMaxFileSize: // 1009 res.writeHead(413).end('Total upload size exceeded'); break; case formidableErrors.maxFieldsExceeded: // 1007 res.writeHead(413).end('Too many fields'); break; case formidableErrors.maxFilesExceeded: // 1015 res.writeHead(413).end('Too many files'); break; case formidableErrors.missingContentType: // 1011 res.writeHead(400).end('Missing Content-Type header'); break; case formidableErrors.aborted: // 1002 res.writeHead(400).end('Request aborted'); break; default: res.writeHead(err.httpCode || 500).end(err.message); } } }); server.listen(8080); ``` -------------------------------- ### Formidable Options Source: https://github.com/node-formidable/formidable/blob/master/README.md Configure Formidable's behavior by passing an options object during initialization. These options control aspects like encoding, upload directories, file size limits, and more. ```APIDOC ## Options See it's defaults in [src/Formidable.js DEFAULT_OPTIONS](./src/Formidable.js) (the `DEFAULT_OPTIONS` constant). - `options.encoding` **{string}** - default `'utf-8'`; sets encoding for incoming form fields, - `options.uploadDir` **{string}** - default `os.tmpdir()`; the directory for placing file uploads in. You can move them later by using `fs.rename()`. - `options.keepExtensions` **{boolean}** - default `false`; to include the extensions of the original files or not - `options.allowEmptyFiles` **{boolean}** - default `false`; allow upload empty files - `options.minFileSize` **{number}** - default `1` (1byte); the minium size of uploaded file. - `options.maxFiles` **{number}** - default `Infinity`; limit the amount of uploaded files, set Infinity for unlimited - `options.maxFileSize` **{number}** - default `200 * 1024 * 1024` (200mb); limit the size of each uploaded file. - `options.maxTotalFileSize` **{number}** - default `options.maxFileSize`; limit the size of the batch of uploaded files. - `options.maxFields` **{number}** - default `1000`; limit the number of fields, set Infinity for unlimited - `options.maxFieldsSize` **{number}** - default `20 * 1024 * 1024` (20mb); limit the amount of memory all fields together (except files) can allocate in bytes. - `options.hashAlgorithm` **{string | false}** - default `false`; include checksums calculated for incoming files, set this to some hash algorithm, see [crypto.createHash](https://nodejs.org/api/crypto.html#crypto_crypto_createhash_algorithm_options) for available algorithms - `options.fileWriteStreamHandler` **{function}** - default `null`, which by default writes to host machine file system every file parsed; The function should return an instance of a [Writable stream](https://nodejs.org/api/stream.html#stream_class_stream_writable) that will receive the uploaded file data. With this option, you can have any custom behavior regarding where the uploaded file data will be streamed for. If you are looking to write the file uploaded in other types of cloud storages (AWS S3, Azure blob storage, Google cloud storage) or private file storage, this is the option you're looking for. When this option is defined the default behavior of writing the file in the host machine file system is lost. - `options.filename` **{function}** - default `undefined` Use it to control newFilename. Must return a string. Will be joined with options.uploadDir. - `options.filter` **{function}** - default function that always returns true. Use it to filter files before they are uploaded. Must return a boolean. Will not make the form.parse error - `options.createDirsFromUploads` **{boolean}** - default false. If true, makes direct folder uploads possible. Use `` to create a form to upload folders. Has to be used with the options `options.uploadDir` and `options.filename` where `options.filename` has to return a string with the character `/` for folders to be created. The base will be `options.uploadDir`. #### `options.filename` **{function}** function (name, ext, part, form) -> string where part can be decomposed as ```js const { originalFilename, mimetype } = part; ``` _**Note:** If this size of combined fields, or size of some file is exceeded, an `'error'` event is fired._ ```js // The amount of bytes received for this form so far. form.bytesReceived; ``` ```js // The expected number of bytes in this form. form.bytesExpected; ``` ``` -------------------------------- ### Parse Request with Promise Source: https://github.com/node-formidable/formidable/blob/master/README.md An alternative to the callback method, this demonstrates parsing a request using Promises and `async/await` syntax for cleaner asynchronous code. ```javascript // with Promise const [fields, files] = await form.parse(req); ``` -------------------------------- ### Configure Enabled Plugins Source: https://github.com/node-formidable/formidable/blob/master/README.md Initialize Formidable with specific plugins enabled by passing an array to `enabledPlugins`. This allows disabling default parsers like multipart. ```javascript import formidable, { octetstream, querystring, json } from "formidable"; const form = formidable({ hashAlgorithm: "sha1", enabledPlugins: [octetstream, querystring, json], }); ``` -------------------------------- ### Register and Use a Custom Plugin Source: https://github.com/node-formidable/formidable/blob/master/README.md Instantiate Formidable and then use the `.use()` method to register a custom plugin function. The plugin can access the Formidable instance via `self` or `this`. ```javascript const form = formidable({ keepExtensions: true }); form.use((self, options) => { // self === this === form console.log("woohoo, custom plugin"); // do your stuff; check `src/plugins` for inspiration }); form.parse(req, (error, fields, files) => { console.log("done!"); }); ``` -------------------------------- ### Listen for Progress Events Source: https://github.com/node-formidable/formidable/blob/master/README.md Use the `'progress'` event to monitor the upload progress. This event emits the number of bytes received and expected. Use this for server-side progress bars only. ```javascript form.on("progress", (bytesReceived, bytesExpected) => {}); ``` -------------------------------- ### File Filtering with `options.filter` Source: https://github.com/node-formidable/formidable/blob/master/README.md Configure a filter function to selectively process files based on their properties. Returning `false` will ignore the file. ```APIDOC ## options.filter ### Description Behaves like `Array.filter`: Returning `false` will simply ignore the file and go to the next. ### Parameters - **name** (string) - The name of the file. - **originalFilename** (string) - The original filename. - **mimetype** (string) - The MIME type of the file. ### Return Value - **boolean**: `true` to keep the file, `false` to ignore it. ### Example ```javascript const options = { filter: function ({ name, originalFilename, mimetype }) { // keep only images return mimetype && mimetype.includes("image"); }, }; ``` ### Error Handling Example ```javascript let cancelUploads = false; // create variable at the same scope as form const options = { filter: function ({ name, originalFilename, mimetype }) { // keep only images const valid = mimetype && mimetype.includes("image"); if (!valid) { form.emit("error", new formidableErrors.default("invalid type", 0, 400)); // optional make form.parse error cancelUploads = true; //variable to make filter return false after the first problem } return valid && !cancelUploads; }, }; ``` ``` -------------------------------- ### Specify Upload Directory Source: https://github.com/node-formidable/formidable/blob/master/README.md Configure the upload directory for formidable. Using `__dirname` makes the path relative to the current script, while omitting it uses the current working directory. ```javascript "${__dirname}/../uploads"; ``` -------------------------------- ### Benchmark Results Across Node.js Versions Source: https://github.com/node-formidable/formidable/blob/master/README.md Performance comparison of the multipart parser across Node.js 8, 10, 12, and 13. Results are measured in megabytes per second (mb/sec). ```bash ~/github/node-formidable master ❯ nve --parallel 8 10 12 13 node benchmark/bench-multipart-parser.js ⬢ Node 8 1261.08 mb/sec ⬢ Node 10 1113.04 mb/sec ⬢ Node 12 2107.00 mb/sec ⬢ Node 13 2566.42 mb/sec ``` -------------------------------- ### Ensure Upload Directories Exist Source: https://github.com/node-formidable/formidable/blob/master/README.md Use `filesac` to synchronously create necessary directories for uploads. This prevents files from being silently discarded if the target directory is missing. ```javascript import { createNecessaryDirectoriesSync } from "filesac"; const uploadPath = `${__dirname}/../uploads`; createNecessaryDirectoriesSync(`${uploadPath}/x`); ``` -------------------------------- ### .use(plugin: Plugin) Source: https://github.com/node-formidable/formidable/blob/master/README.md Extends the Formidable library by allowing custom plugins to be added. These plugins can modify or extend the parsing capabilities of Formidable. ```APIDOC ## .use(plugin: Plugin) ### Description A method that allows you to extend the Formidable library. By default we include 4 plugins, which essentially are adapters to plug the different built-in parsers. The plugins added by this method are always enabled. See [src/plugins/](./src/plugins/) for more detailed look on default plugins. The `plugin` param has such signature: ```typescript function(formidable: Formidable, options: Options): void; ``` The architecture is simple. The `plugin` is a function that is passed with the Formidable instance (the `form` across the README examples) and the options. Note: the plugin function's `this` context is also the same instance. ### Request Example ```js const form = formidable({ keepExtensions: true }); form.use((self, options) => { // self === this === form console.log("woohoo, custom plugin"); // do your stuff; check `src/plugins` for inspiration }); form.parse(req, (error, fields, files) => { console.log("done!"); }); ``` **Important to note**, is that inside plugin `this.options`, `self.options` and `options` MAY or MAY NOT be the same. General best practice is to always use the `this`, so you can later test your plugin independently and more easily. If you want to disable some parsing capabilities of Formidable, you can disable the plugin which corresponds to the parser. For example, if you want to disable multipart parsing (so the [src/parsers/Multipart.js](./src/parsers/Multipart.js) which is used in [src/plugins/multipart.js](./src/plugins/multipart.js)), then you can remove it from the `options.enabledPlugins`, like so ### Request Example ```js import formidable, { octetstream, querystring, json } from "formidable"; const form = formidable({ hashAlgorithm: "sha1", enabledPlugins: [octetstream, querystring, json], }); ``` **Be aware** that the order _MAY_ be important too. The names corresponds 1:1 to files in [src/plugins/](./src/plugins) folder. Pull requests for new built-in plugins MAY be accepted - for example, more advanced querystring parser. Add your plugin as a new file in `src/plugins/` folder (lowercased) and follow how the other plugins are made. ``` -------------------------------- ### form.parse with Express.js Source: https://context7.com/node-formidable/formidable/llms.txt Demonstrates how to use Formidable's `parse` method directly within an Express.js application without requiring special middleware. ```APIDOC ## `form.parse` with Express.js Formidable works directly with Express by consuming the raw Node.js request stream (`req` from Express is a native `http.IncomingMessage`); no special middleware is required. ```js import express from 'express'; import formidable from 'formidable'; const app = express(); app.post('/api/upload', (req, res, next) => { const form = formidable({ uploadDir: '/tmp/uploads', keepExtensions: true, maxFiles: 5, maxFileSize: 50 * 1024 * 1024, // 50 MB }); form.parse(req, (err, fields, files) => { if (err) { next(err); return; } // fields.title -> ['My Title'] // files.document -> [PersistentFile { ... }] res.json({ fields, files }); }); }); app.listen(3000); ``` ``` -------------------------------- ### Custom File Naming with `options.filename` Source: https://context7.com/node-formidable/formidable/llms.txt Provide a synchronous function to `options.filename` to control how uploaded files are named on disk. The returned string is joined with `options.uploadDir`. ```javascript import path from 'node:path'; import formidable from 'formidable'; import http from 'node:http'; const server = http.createServer(async (req, res) => { let counter = 0; const form = formidable({ uploadDir: '/tmp/uploads', keepExtensions: true, filename(name, ext, part, form) { // name = base name without extension // ext = extension including dot, e.g. '.jpg' // part = { originalFilename, mimetype, ... } counter += 1; const safeName = name.replace(/[^a-z0-9]/gi, '_').toLowerCase(); return `${Date.now()}_${counter}_${safeName}${ext}`; // e.g. -> /tmp/uploads/1700000000000_1_photo.jpg }, }); const [fields, files] = await form.parse(req); res.end(JSON.stringify({ files })); }); server.listen(8080); ``` -------------------------------- ### form.parse with Koa Source: https://context7.com/node-formidable/formidable/llms.txt Demonstrates how to use `form.parse` with Koa, ensuring to pass `ctx.req` (the raw Node.js request) instead of `ctx.request` (the Koa request wrapper). ```APIDOC ## `form.parse` with Koa When using Koa, pass `ctx.req` (the raw Node.js request), not `ctx.request` (the Koa request wrapper). ```js import Koa from 'koa'; import formidable from 'formidable'; const app = new Koa(); app.use(async (ctx, next) => { if (ctx.url === '/api/upload' && ctx.method.toLowerCase() === 'post') { const form = formidable({ keepExtensions: true }); const [fields, files] = await new Promise((resolve, reject) => { form.parse(ctx.req, (err, fields, files) => { // note: ctx.req, not ctx.request if (err) reject(err); else resolve([fields, files]); }); }); ctx.status = 200; ctx.set('Content-Type', 'application/json'); ctx.body = JSON.stringify({ fields, files }, null, 2); await next(); } }); app.listen(3000); ``` ``` -------------------------------- ### Process Received Files with formidable Source: https://github.com/node-formidable/formidable/blob/master/README.md The 'file' event is emitted when a field/file pair is received. It's too late to change the filepath at this point, but file.hash is available if options.hash was used. ```javascript form.on("file", (formname, file) => { // same as fileBegin, except // it is too late to change file.filepath // file.hash is available if options.hash was used }); ``` -------------------------------- ### Compute File Checksums with hashAlgorithm Source: https://context7.com/node-formidable/formidable/llms.txt Set `hashAlgorithm` to compute file checksums. After parsing, `file.hash` will contain the hex digest. Supported algorithms are those of Node.js `crypto.createHash`. ```javascript import http from 'node:http'; import formidable from 'formidable'; const server = http.createServer(async (req, res) => { const form = formidable({ uploadDir: '/tmp/uploads', hashAlgorithm: 'sha256', }); const [fields, files] = await form.parse(req); for (const [fieldName, fileList] of Object.entries(files)) { for (const file of fileList) { console.log(`${file.originalFilename}: sha256=${file.hash}`); // e.g. photo.jpg: sha256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 } } res.end('ok'); }); server.listen(8080); ``` -------------------------------- ### options.hashAlgorithm Source: https://context7.com/node-formidable/formidable/llms.txt Compute file checksums using Node.js crypto algorithms. The hex digest is stored in `file.hash` after parsing. ```APIDOC ## `options.hashAlgorithm` — Compute file checksums Set `hashAlgorithm` to any algorithm supported by Node.js `crypto.createHash` (e.g. `'sha256'`, `'md5'`). After parsing, `file.hash` holds the hex digest. ```js import http from 'node:http'; import formidable from 'formidable'; const server = http.createServer(async (req, res) => { const form = formidable({ uploadDir: '/tmp/uploads', hashAlgorithm: 'sha256', }); const [fields, files] = await form.parse(req); for (const [fieldName, fileList] of Object.entries(files)) { for (const file of fileList) { console.log(`${file.originalFilename}: sha256=${file.hash}`); // e.g. photo.jpg: sha256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 } } res.end('ok'); }); server.listen(8080); ``` ``` -------------------------------- ### options.createDirsFromUploads Source: https://context7.com/node-formidable/formidable/llms.txt Preserve uploaded folder structure when `createDirsFromUploads` is true. This is useful for HTML inputs with the `webkitdirectory` attribute. ```APIDOC ## `options.createDirsFromUploads` — Preserve uploaded folder structure When `createDirsFromUploads: true`, the `options.filename` function can return a path with `/` separators, and Formidable will create the required subdirectories under `uploadDir`. This is used in combination with `` HTML inputs. ```js import path from 'node:path'; import formidable from 'formidable'; import http from 'node:http'; const BASE_UPLOAD_DIR = '/tmp/uploads'; const server = http.createServer(async (req, res) => { const form = formidable({ uploadDir: BASE_UPLOAD_DIR, createDirsFromUploads: true, filename(name, ext, part) { // originalFilename may be something like "myFolder/sub/file.txt" // Return the relative path; formidable will create the directories return part.originalFilename; // e.g. "project/src/index.js" // Final path: /tmp/uploads/project/src/index.js }, }); const [fields, files] = await form.parse(req); res.end(JSON.stringify({ files })); }); server.listen(8080); ``` ``` -------------------------------- ### Extend Formidable with Custom Plugins Source: https://context7.com/node-formidable/formidable/llms.txt Plugins extend Formidable's functionality. They are functions with the signature `(formidable, options) => void`. Built-in plugins can be selectively enabled or disabled via `options.enabledPlugins`. ```javascript import formidable, { octetstream, querystring, json } from 'formidable'; import http from 'node:http'; // --- Disable multipart plugin (accept only JSON and urlencoded) --- const form = formidable({ enabledPlugins: [querystring, json], // multipart and octetstream are excluded }); // --- Add a custom plugin for logging --- form.use((self, options) => { self.on('fileBegin', (formname, file) => { console.log(`[plugin] Starting upload: ${file.originalFilename}`); }); self.on('file', (formname, file) => { console.log(`[plugin] Finished: ${file.originalFilename} (${file.size} bytes)`); }); }); const server = http.createServer(async (req, res) => { try { const [fields, files] = await form.parse(req); res.end(JSON.stringify({ fields, files })); } catch (err) { res.writeHead(400).end(err.message); } }); server.listen(8080); ``` -------------------------------- ### form.onPart Source: https://context7.com/node-formidable/formidable/llms.txt Intercept raw multipart parts to handle specific parts manually. Call `form._handlePart(part)` for parts that should be processed normally by Formidable. ```APIDOC ## `form.onPart` — Intercept raw multipart parts Override `form.onPart` to handle specific parts manually. Call `form._handlePart(part)` for parts you want Formidable to process normally. ```js import http from 'node:http'; import formidable from 'formidable'; const server = http.createServer((req, res) => { const form = formidable(); // Only let Formidable handle text fields; handle files manually form.onPart = (part) => { if (!part.originalFilename && !part.mimetype) { // It's a text field — let formidable handle it normally form._handlePart(part); return; } // It's a file — handle it ourselves (e.g. discard or inspect) console.log(`Intercepted file part: ${part.originalFilename}`); part.on('data', (buffer) => { console.log(` chunk: ${buffer.length} bytes`); }); part.on('end', () => { console.log(` done: ${part.originalFilename}`); }); }; form.parse(req, (err, fields) => { if (err) { res.writeHead(400).end(err.message); return; } res.end(JSON.stringify({ fields })); }); }); server.listen(8080); ``` ``` -------------------------------- ### File Interface Source: https://github.com/node-formidable/formidable/blob/master/README.md Defines the structure of a file object processed by Formidable, including properties like size, filepath, and original filename. ```APIDOC ## File Interface ```ts export interface File { // The size of the uploaded file in bytes. // If the file is still being uploaded (see `'fileBegin'` event), // this property says how many bytes of the file have been written to disk yet. file.size: number; // The path this file is being written to. You can modify this in the `'fileBegin'` event in // case you are unhappy with the way formidable generates a temporary path for your files. file.filepath: string; // The name this file had according to the uploading client. file.originalFilename: string | null; // calculated based on options provided file.newFilename: string | null; // The mime type of this file, according to the uploading client. file.mimetype: string | null; // A Date object (or `null`) containing the time this file was last written to. // Mostly here for compatibility with the [W3C File API Draft](http://dev.w3.org/2006/webapi/FileAPI/). file.mtime: Date | null; file.hashAlgorithm: false | |'sha1' | 'md5' | 'sha256' // If `options.hashAlgorithm` calculation was set, you can read the hex digest out of this var (at the end it will be a string) file.hash: string | object | null; } ``` ### file.toJSON() This method returns a JSON-representation of the file, allowing you to `JSON.stringify()` the file which is useful for logging and responding to requests. ``` -------------------------------- ### form.use(plugin) Source: https://context7.com/node-formidable/formidable/llms.txt Extend Formidable with custom plugins or selectively disable built-in plugins. Plugins are functions that modify Formidable's behavior. ```APIDOC ## `form.use(plugin)` — Extend Formidable with custom plugins Plugins are functions with the signature `(formidable, options) => void` (or async). The four built-in plugins (`multipart`, `querystring`, `json`, `octetstream`) can be selectively disabled by passing a subset to `options.enabledPlugins`. ```js import formidable, { octetstream, querystring, json } from 'formidable'; import http from 'node:http'; // --- Disable multipart plugin (accept only JSON and urlencoded) --- const form = formidable({ enabledPlugins: [querystring, json], // multipart and octetstream are excluded }); // --- Add a custom plugin for logging --- form.use((self, options) => { self.on('fileBegin', (formname, file) => { console.log(`[plugin] Starting upload: ${file.originalFilename}`); }); self.on('file', (formname, file) => { console.log(`[plugin] Finished: ${file.originalFilename} (${file.size} bytes)`); }); }); const server = http.createServer(async (req, res) => { try { const [fields, files] = await form.parse(req); res.end(JSON.stringify({ fields, files })); } catch (err) { res.writeHead(400).end(err.message); } }); server.listen(8080); ``` ``` -------------------------------- ### Event: 'file' Source: https://github.com/node-formidable/formidable/blob/master/README.md Emitted when a complete file/field pair has been received. The file path cannot be changed at this stage. ```APIDOC ## Event: 'file' ### Description Emitted whenever a field / file pair has been received. `file` is an instance of `File`. ### Parameters - **formname** (string) - The name of the form field. - **file** (object) - An object containing file details (same properties as in 'fileBegin', but `filepath` cannot be changed). - **hash** (string, optional) - Available if `options.hash` was used. ### Example ```js form.on("file", (formname, file) => { // It is too late to change file.filepath // file.hash is available if options.hash was used }); ``` ``` -------------------------------- ### Event: 'end' Source: https://github.com/node-formidable/formidable/blob/master/README.md Emitted when the entire request has been received and all files have been flushed to disk. Ideal for sending responses. ```APIDOC ## Event: 'end' ### Description Emitted when the entire request has been received, and all contained files have finished flushing to disk. This is a great place for you to send your response. ### Example ```js form.on("end", () => {}); ``` ``` -------------------------------- ### API Load Testing with Bombardier Source: https://github.com/node-formidable/formidable/blob/master/benchmark/2022-11-30-i5-9600k.txt Use bombardier to perform load testing on a POST endpoint. This command simulates multiple connections and measures request statistics and throughput. ```bash bombardier --body-file="./README.md" --method=POST --duration=10s --connections=100 http://localhost:3000/api/upload ``` -------------------------------- ### Add Custom Plugin to Formidable Source: https://github.com/node-formidable/formidable/blob/master/README.md Use the `.use()` method to extend Formidable with custom functionality. The plugin function receives the Formidable instance and options. ```typescript function(formidable: Formidable, options: Options): void; ``` -------------------------------- ### Convert File to Base64 Request Source: https://github.com/node-formidable/formidable/blob/master/test/tools/base64.html Handles form submission by reading a file, encoding it to Base64, and making a request. Ensure the output is saved with Windows (CRLF) line endings. ```javascript function form_submit(e) { console.log(e); var resultOutput = document.getElementById("resultOutput"); var fileInput = document.getElementById("fileInput"); var fieldInput = document.getElementById("fieldInput"); makeRequestBase64(fileInput.files[0], fieldInput.value, function ( err, result ) { resultOutput.value = result; }); return false; } function makeRequestBase64(file, fieldName, cb) { var boundary = "\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/"; var crlf = "\r\n"; var reader = new FileReader(); reader.onload = function (e) { var body = ""; body += "--" + boundary + crlf; body += 'Content-Disposition: form-data; name="' + fieldName + '"; filename="' + escape(file.name) + '"' + crlf; body += "Content-Type: " + file.type + "" + crlf; body += "Content-Transfer-Encoding: base64" + crlf; body += crlf; body += e.target.result.substring(e.target.result.indexOf(",") + 1) + crlf; body += "--" + boundary + "--"; var head = ""; head += "POST /upload HTTP/1.1" + crlf; head += "Host: localhost:8080" + crlf; head += "Content-Type: multipart/form-data; boundary=" + boundary + "" + crlf; head += "Content-Length: " + body.length + "" + crlf; cb(null, head + crlf + body); }; reader.readAsDataURL(file); } ``` -------------------------------- ### Events Source: https://github.com/node-formidable/formidable/blob/master/README.md Details the events emitted by Formidable during the parsing process, such as 'progress', 'field', and 'fileBegin'. ```APIDOC ## Events ### 'progress' Emitted after each incoming chunk of data that has been parsed. Can be used to roll your own progress bar. **Warning** Use this only for server side progress bar. On the client side better use `XMLHttpRequest` with `xhr.upload.onprogress =` ### Request Example ```js form.on("progress", (bytesReceived, bytesExpected) => {}); ``` ### 'field' Emitted whenever a field / value pair has been received. ### Request Example ```js form.on("field", (name, value) => {}); ``` ```