it-multipart: Async Iterable Multipart Parser
it-multipart is a JavaScript library designed to parse HTTP multipart messages using async iterables. It provides a robust and modern approach to handling streaming data from HTTP requests, particularly useful for file uploads or complex form data. Currently at version 3.0.14, it is part of the broader `it` (InterPlanetary Stream) ecosystem, which emphasizes composable, stream-based utilities. The project demonstrates active maintenance, with frequent updates to various `it-*` packages within its monorepo, suggesting a stable and evolving codebase. Its key differentiator lies in its deep integration with JavaScript's async iterable protocol, making it highly efficient for non-blocking I/O operations and suitable for both Node.js server environments and potentially browser-side stream processing where async iterables are supported. It ships with TypeScript types, ensuring a better developer experience for TypeScript users.
Common errors
-
TypeError: multipart is not a function or not iterable
cause Attempting to use `require` with `it-multipart` in a strict ESM context, or an incorrect named import.fixEnsure you are using `import multipart from 'it-multipart'` in ESM modules. If using CommonJS, verify the environment's support for importing ESM default exports, or use `const multipart = require('it-multipart')` and test its functionality. -
Error: stream has ended or has no more data
cause Attempting to read from `part.body` after it has been fully consumed or if the upstream stream has closed prematurely, possibly due to not consuming `part.body` for a previous part.fixConfirm that `part.body` is fully consumed for each part within its loop, and that the upstream HTTP request stream is correctly handled and not closed before all parts are processed.
Warnings
- gotcha When iterating over multipart parts, the `part.body` async iterable for the current part MUST be fully consumed before the next part can be emitted by the `multipart` parser. Failing to consume `part.body` will lead to stalls or incomplete parsing.
- breaking The `multipart` function now expects the `boundary` string to be passed as a second argument, or inferred from the `req.headers['content-type']`. In previous versions, the boundary might have been automatically extracted or handled differently. Explicitly extracting and passing the boundary ensures correct parsing.
- gotcha The `it-multipart` library is built around async iterables. Directly attempting to use it with older Node.js stream APIs (e.g., piping to traditional `Writable` streams) without proper adaptation (e.g., using `it-pipe` or manually iterating) can lead to unexpected behavior or errors.
Install
-
npm install it-multipart -
yarn add it-multipart -
pnpm add it-multipart
Imports
- multipart
import { multipart } from 'it-multipart'import multipart from 'it-multipart'
- multipart (CommonJS)
const { multipart } = require('it-multipart')const multipart = require('it-multipart') - Part
import type { Part } from 'it-multipart'
Quickstart
import http from 'http'
import multipart from 'it-multipart'
const server = http.createServer(async (req, res) => {
if (req.method === 'POST' && req.headers['content-type']) {
try {
const boundary = req.headers['content-type'].split('boundary=')[1]
if (!boundary) {
res.writeHead(400, { 'Content-Type': 'text/plain' })
res.end('Missing boundary in Content-Type header')
return
}
for await (const part of multipart(req, boundary)) {
console.log(`Received part with headers:`, part.headers)
let partContent = ''
// nb. part.body must be consumed before the next part is emitted
for await (const chunk of part.body) {
partContent += chunk.toString()
}
console.log(`Part name: ${part.name}, Content:`, partContent)
}
console.log('Finished parsing multipart message.')
res.writeHead(200, { 'Content-Type': 'text/plain' })
res.end('Multipart message parsed successfully.')
} catch (error) {
console.error('Error parsing multipart message:', error)
res.writeHead(500, { 'Content-Type': 'text/plain' })
res.end('Error parsing multipart message: ' + error.message)
}
} else {
res.writeHead(404, { 'Content-Type': 'text/plain' })
res.end('Not Found or Unsupported Method')
}
})
server.listen(5001, () => {
console.log('Server listening on port 5001')
})
// Example usage with curl:
// curl -X POST -H "Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW" -F "field1=value1" -F "file1=@./package.json" http://localhost:5001