Meros: Multipart Response Utility
Meros is a lightweight (642B gzipped) utility designed to simplify the parsing of `multipart/mixed` HTTP responses, a common pattern in technologies like GraphQL for deferred or streamed results. Currently at version 1.3.2, the project appears actively maintained with a stable release cadence. Its key differentiators include a zero-dependency runtime, a minimal footprint, high performance, and seamless integration with `fetch` and `rxjs`. It supports both Node.js (requiring `node >=13`) and browser environments, automatically parsing JSON content within parts. Meros returns an `AsyncGenerator` for `multipart/mixed` responses, or the original `Response` object for other content types, offering flexibility for use in middleware or chained `fetch` calls.
Common errors
-
TypeError: parts is not async iterable
cause This error occurs when attempting to use `for await (const part of parts)` on the value returned by `meros` when the HTTP response's `Content-Type` header was not `multipart/mixed`. In such cases, `meros` returns the original `Response` object, which is not an async iterable.fixBefore iterating, always check if the returned `parts` object is an async iterable using `if (parts && typeof (parts as any)[Symbol.asyncIterator] === 'function')`. If not, process `parts` as a standard `Response` object (e.g., `parts.json()`). -
ReferenceError: require is not defined
cause Attempting to use `require('meros')` or `require('meros/node')` in an environment that expects ECMAScript Modules (ESM) syntax, such as a modern Node.js project or a browser module without proper CommonJS transpilation.fixMeros is primarily designed for ESM. Update your import statements to use `import { meros } from 'meros';` (or specific subpath imports) and ensure your project's `package.json` specifies `"type": "module"` or your build setup correctly handles ESM.
Warnings
- gotcha Meros returns an `AsyncGenerator<Part>` only if the `content-type` HTTP header is `multipart/mixed`. For any other content type, it resolves with the original `Response` object. Developers must explicitly check the return type before attempting to iterate over `parts`.
- gotcha The main `meros` entry point (`import { meros } from 'meros';`) relies on bundler or environment detection to load the correct browser or Node.js-specific code. This can sometimes lead to unexpected behavior or larger bundle sizes if not configured correctly, or if a browser build is incorrectly served in Node or vice-versa.
Install
-
npm install meros -
yarn add meros -
pnpm add meros
Imports
- meros
import meros from 'meros';
import { meros } from 'meros'; - meros (Browser)
import { meros } from 'meros';import { meros } from 'meros/browser'; - meros (Node.js)
const { meros } = require('meros/node');import { meros } from 'meros/node';
Quickstart
import { meros } from 'meros';
async function fetchAndProcessMultipart() {
// Simulate a multipart/mixed response or a regular JSON response
// In a real application, replace with your actual fetch call
const mockFetch = async (url: string) => {
if (url === '/api/multipart') {
// Example multipart response
return new Response(
`--boundary\r\nContent-Type: application/json\r\n\r\n{"data": "part1"}\r\n--boundary\r\nContent-Type: text/plain\r\n\r\nhello from part 2\r\n--boundary--`,
{
headers: { 'Content-Type': 'multipart/mixed; boundary=boundary' }
}
);
} else {
// Example non-multipart JSON response
return new Response(JSON.stringify({ message: 'Not multipart' }), {
headers: { 'Content-Type': 'application/json' }
});
}
};
try {
const response = await mockFetch('/api/multipart'); // Try with '/api/json' to see the other path
const parts = await meros(response);
if (parts && typeof (parts as any)[Symbol.asyncIterator] === 'function') {
console.log('Processing multipart response:');
for await (const part of parts) {
if (part.json) {
console.log(' JSON Part:', part.body);
} else {
console.log(' Text/Other Part:', new TextDecoder().decode(part.body as Uint8Array));
}
}
} else {
console.log('Not a multipart response, processing as regular response:');
const data = await (parts as Response).json();
console.log(' Response Data:', data);
}
} catch (error) {
console.error('Error fetching or processing:', error);
}
}
fetchAndProcessMultipart();