{"id":13455182,"url":"https://github.com/octet-stream/then-busboy","last_synced_at":"2025-04-10T18:31:35.116Z","repository":{"id":11827501,"uuid":"70698049","full_name":"octet-stream/then-busboy","owner":"octet-stream","description":"Promise-based wrapper around Busboy. Processes multipart/form-data request body and returns it in a single object.","archived":false,"fork":false,"pushed_at":"2024-02-19T15:07:35.000Z","size":1472,"stargazers_count":9,"open_issues_count":0,"forks_count":3,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-03T16:01:46.244Z","etag":null,"topics":["async-await","body-parser","busboy","file-upload","form-data","javascript","multipart","nodejs-library","promise","typescript","wrapper"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/then-busboy","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/octet-stream.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"license","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-10-12T12:32:23.000Z","updated_at":"2023-10-25T10:49:16.000Z","dependencies_parsed_at":"2022-09-06T00:40:08.654Z","dependency_job_id":"aa56b160-a86f-4fc0-ac07-31880d9b16de","html_url":"https://github.com/octet-stream/then-busboy","commit_stats":{"total_commits":502,"total_committers":5,"mean_commits":100.4,"dds":0.04980079681274896,"last_synced_commit":"e05c968de15bea9ab9153802b4a68948c4b9dd35"},"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/octet-stream%2Fthen-busboy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/octet-stream%2Fthen-busboy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/octet-stream%2Fthen-busboy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/octet-stream%2Fthen-busboy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/octet-stream","download_url":"https://codeload.github.com/octet-stream/then-busboy/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248271765,"owners_count":21075800,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async-await","body-parser","busboy","file-upload","form-data","javascript","multipart","nodejs-library","promise","typescript","wrapper"],"created_at":"2024-07-31T08:01:02.158Z","updated_at":"2025-04-10T18:31:34.513Z","avatar_url":"https://github.com/octet-stream.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# then-busboy\n\nPromise-based wrapper around Busboy. Processes multipart/form-data request body and returns it in a single object.\n\n[![Code Coverage](https://codecov.io/github/octet-stream/then-busboy/coverage.svg?branch=master)](https://codecov.io/github/octet-stream/then-busboy?branch=master)\n[![CI](https://github.com/octet-stream/then-busboy/workflows/CI/badge.svg)](https://github.com/octet-stream/then-busboy/actions/workflows/ci.yml)\n[![ESLint](https://github.com/octet-stream/then-busboy/workflows/ESLint/badge.svg)](https://github.com/octet-stream/then-busboy/actions/workflows/eslint.yml)\n\n## Installation\n\nYou can install `then-busboy` from npm:\n\n```\nnpm install --save then-busboy\n```\n\nOr with yarn:\n\n```\nyarn add then-busboy\n```\n\n## Usage\n\nBecause then-busboy can process `multipart/form-data` bodies from AsyncIterable sources, you can use it with different HTTP frameworks, or with Node.js http module, or even with [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) object (see the 4th example).\n\n1. Let's take a look at the example with `http` module from Node.js.\nWe'll write a simple server that will parse form-data request, read files content and then send them back as JSON:\n\n```js\nimport {createServer} from \"http\"\nimport {parse} from \"then-busboy\"\n\nconst handler = (req, res) =\u003e parse(req)\n  .then(async body =\u003e {\n    const result = []\n    for (const [path, value] of body) {\n      result.push([path, isFile(value) ? await value.text() : value])\n    }\n\n    res.setHeader(\"Content-Type\", \"application/json\")\n    res.end(JSON.stringify(Body.json(result)))\n  })\n  .catch(error =\u003e {\n    res.statusCode = error.status || 500\n    res.end(error.message)\n  })\n\ncreateServer(handler)\n  .listen(2319, () =\u003e console.log(\"Server started on http://localhost:2319\"))\n```\n\n**Note:** You can use [asynchronous function](https://github.com/tc39/ecmascript-asyncawait) syntax,\nbecause then-busboy always returns a Promise.\n\n2. Miniaml multipart middleware implementation for [Koa.js](https://koajs.com):\n\n```js\nimport {parse} from \"then-busboy\"\n\nasync function multipart(ctx, next) {\n  if ([\"post\", \"put\"].includes(ctx.method.toLowerCase()) === false) {\n    return next()\n  }\n\n  if (ctx.is(\"multipart/form-data\") === false) {\n    return next()\n  }\n\n  const body = await parse(ctx.req)\n\n  ctx.request.body = body.json()\n\n  return next()\n}\n\nexport default multipart\n```\n\n3. You can also use `AsyncIterable` value as the input. That way you can parse FormData from other that just HTTP requests. Let's take a loook at the example with [`form-data-encoder`](https://github.com/octet-stream/form-data-encoder) and [`formdata-node`](https://github.com/octet-stream/form-data) as the input:\n\n```js\nimport {fileFromPath} from \"formdata-node/file-from-path\"\nimport {FormDataEncoder} from \"form-data-encoder\"\nimport {FormData} from \"formdata-node\"\nimport {parse} from \"then-busboy\"\n\nconst form = new FormData()\n\nform.set(\"greeting\", \"Hello, World!\")\nform.set(\"file\", new File([\"On Soviet Moon landscape see binoculars through YOU\"], \"file.txt\"))\nform.set(\"fileFromPath\", await fileFromPath(\"path/to/a/file\"))\n\nconst encoder = new FormDataEncoder(form)\n\nconst body = await parse(encoder, {\n  headers: {\n    \"content-type\": encoder.contentType\n  }\n})\n\nconsole.log(body.json()) // -\u003e {greeting: string, file: BodyFile, fileFromPath: BodyFile}\n```\n\n4. Because `then-busboy` accepts AsyncIterable as the input, you can also read [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) body like that:\n\n```js\nimport {Response, FormData} from \"node-fetch\"\nimport {parse} from \"then-bosboy\"\nconst form = new FormData()\n\nform.set(\"greeting\", \"Hello, World!\")\nform.set(\"file\", new File([\"On Soviet Moon landscape see binoculars through YOU\"], \"file.txt\"))\n\nconst response = new Respone(form)\n// then-busboy will parse the input and return its own Body instance from which you can create a complete object by calling .json() method or a FormData using .formData() method.\n// The difference with Response.formData() is that then-busboy will save all files to file system and create a *reference* to each of them,\n// while Response (currently) will dump them into RAM, which can be less efficient in some scenarious\nconst body = await parse(response.body, {\n  headers: {\n    \"content-type\": response.headers.get(\"content-type\")\n  }\n})\n\nbody.json() // -\u003e {greeting: string, file: BodyFile}\nbody.formData() // -\u003e FormData\n```\n\n## API\n\n### `parse(source[, options]) -\u003e {Promise\u003cBody\u003e}`\n\n+ **{AsyncIterable}** source – Incoming HTTP multipart/form-data source.\n+ **{object}** [options = {}]\n  - **{boolean}** castTypes – allow to restore type of each value (default – true)\n  - more information about busboy options [here](https://github.com/mscdex/busboy).\n\n### `class Body`\n\n##### `constructor(entries) -\u003e {Body}`\n\nCreate an object that allows to manipulate FormData fields taken `then-busboy`\n\n#### Static methods\n\n##### `from(entries) -\u003e {Body}`\n\nCreate a new Body from given entries. An alias of `new Body(entries)`\n\n  - **{Array\u003c[string[], any]\u003e}** entries – an array of Body initial path-value pairs taken from `then-busboy`\n\n##### `json(value) -\u003e {object}`\n\nReturn an object with data taken from given entries or Body\n\n  - **{Body | Array\u003c[string[], any]\u003e}** – return an object from given Body or entries\n\n##### `formData(value) -\u003e {FormData}`\n\nReturn a FormData instance with data taken from given entries or Body\n\n  - **{Body | Array\u003c[string[], any]\u003e}** – return an FormData from given Body or entries\n\n#### Instance properties\n\n##### `length -\u003e {number}`\n\nReturn an amount of entries and files in current Body instance\n\n#### Instance methods\n\n##### `fields() -\u003e {Body}`\n\nReturn a new Body that contains **fields** only\n\n##### `files() -\u003e {Body}`\n\nReturn a new Body that contains **files** only\n\n##### `json() -\u003e {object}`\n\nReturn an object with data taken the current Body instance\n\n##### `formData() -\u003e {FormData}`\n\nReturn a FormData with data taken the current Body instance\n\n##### `entries() -\u003e {Array\u003c[string[], any]\u003e}`\n\nReturn an array of entries in current Body instance\n\n##### `values() -\u003e {Iterator}`\n\nReturn an iterator allows to go through the Body values\n\n##### `keys() -\u003e {Iterator}`\n\nReturn an iterator allows to go through the Body fields path\n\n### `interface BodyFile`\n\nThis interface reflects internal representation of a File. It is not meant to be constructed manually, but since it's compatible with files from the browsers, you can use these in Body if you need to.\n\n#### Instance properties\n\n##### `name`\n\nContains original name of file taken from the filename property within the form-data.\n\n##### `type`\n\nFile MIME type\n\n##### `enc`\n\nContains a value from transfer encoding header\n\n##### `path`\n\nPath to the file on disk\n\n#### Instance methods\n\n##### `stream() -\u003e {Readable}`\n\nReturns a Readable stream allowing to consume file's content\n\n### `class BodyField`\n\nBodyField class in the internal representation of a regular FormData value.\n\n##### `constructor(value: unknown, name: string[, options]) -\u003e {BodyField}`\n\nCreates a new instance of the BodyField class.\n\n#### Instance properties\n\n##### `name`\n\nReturns the name of the field.\n\n##### `fieldnameTruncated`\n\nIndicates whether the fieldname was truncated.\n\n##### `valueTruncated`\n\nIndicates whether the value was truncated.\n\n##### `enc`\n\nReturns a value from Content-Transfer-Encoding header.\n\n##### `type`\n\nReturns a value from Content-Type header.\n\n#### Instance methods\n\n##### `valueOf() -\u003e {unknown}`\n\nReturns the value of the BodyField.\n\n##### `toString() -\u003e {string}`\n\nReturns string representation of the BodyField value.\n\n## Fields format\n\nthen-busboy can restore an object structure from form-data field names\nif you will follow the naming formats with dots or square brackets:\n\n### Dot notation\n\nThis notation looks similarly to JS object properties accessiong syntax:\n\n```\n# Flat objects looks the same in both notations\n# Note that the following notation examples is just a pseudo code\nname = \"John Doe\"\nage = 25\n```\n\nthen-busboy will return the this object for an example from above:\n\n```json5\n{\n  name: \"John Doe\",\n\n  // By default, non-string values will be converted to their initial type.\n  // So, \"25\" -\u003e 25, \"null\" -\u003e null, \"false\" -\u003e false etc.\n  age: 25\n}\n```\n\nFor deep objects or collections, use dot or brackets as a separator.\n**But don't mix them.**\n\n```\n  rootField.nestedField = \"Some text here\"\n```\n\n```json5\n {\n  rootField: {\n    nestedField: \"Some text here\"\n  }\n }\n```\n\n### Bracket notation\n\n```\nrootField[nestedField] = \"I beat Twilight Sparkle and all I got was this lousy t-shirt\"\n```\n\nBecomes\n\n```json5\n{\n  rootField: {\n    nestedField: \"I beat Twilight Sparkle and all I got was this lousy t-shirt\"\n  }\n}\n```\n\nYou can also send an arrays and collections using bracket format:\n\n```\nmessage[sender] = \"John Doe\"\nmessage[text] = \"Some whatever text message.\"\nmessage[attachments][0][file] = \u003chere is the file content\u003e\nmessage[attachments][0][description] = \"Here is a description of the file\"\n```\n\nthen-busboy returns the following object:\n\n```json5\n{\n  message: {\n    sender: \"John Doe\",\n    text: \"Some whatever text message.\",\n    attachments: [\n      {\n        \"file\": File, // this field will be represended as a File instance\n        \"description\": \"Here is a description of the file\"\n      }\n    ]\n  }\n}\n```\n\nCollections allowed too:\n\n```\n[0][firstName] = \"John\"\n[0][lastName] = \"Doe\"\n[0][dob][day] = \"1\"\n[0][dob][month] = \"Jan.\"\n[0][dob][year] = \"1989\"\n[0][skills][0] = \"Node.js\"\n[0][skills][1] = \"CoffeeScript\"\n[0][skills][2] = \"JavaScript\"\n[0][skills][3] = \"Babel\"\n[1][firstName] = \"Max\"\n[1][lastName] = \"Doe\"\n[1][dob][day] = \"12\"\n[1][dob][month] = \"Mar.\"\n[1][dob][year] = \"1992\"\n[1][skills][0] = \"Python\"\n[1][skills][1] = \"Flask\"\n[1][skills][2] = \"JavaScript\"\n[1][skills][3] = \"Babel\"\n[1][skills][4] = \"React\"\n[1][skills][5] = \"Redux\"\n```\n\nThen you will receive:\n\n```json5\n[\n  {\n    firstName: \"John\",\n    lastName: \"Doe\",\n    dob: {\n      day: 1,\n      month: \"Jan.\",\n      year: 1989\n    },\n    skills: [\"Node.js\", \"CoffeeScript\", \"JavaScript\", \"Babel\"]\n  }, {\n    firstName: \"Max\",\n    lastName: \"Doe\",\n    dob: {\n      day: 12,\n      month: \"Mar.\",\n      year: 1992\n    },\n    skills: [\"Python\", \"Flask\", \"JavaScript\", \"Babel\", \"React\", \"Redux\"]\n  }\n]\n```\n\n## Limits\n\nWhen`limits` options are set, `then-busboy` may reject with HTTP 413 error if specified limit(s) exceeded. That will be a regular error from object [`http-errors`](https://npmjs.com/http-errors) package.\n\n## Related links\n\n* [formdata-node](https://github.com/octet-stream/form-data) spec-compliant [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) implementation for Node.js\n* [@octetstream/object-to-form-data](https://github.com/octet-stream/object-to-form-data) converts JavaScript object to FormData.\n\n## License\n\n[MIT](https://github.com/octet-stream/then-busboy/blob/master/LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foctet-stream%2Fthen-busboy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foctet-stream%2Fthen-busboy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foctet-stream%2Fthen-busboy/lists"}