npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@medley/multipart

v0.3.0

Published

Medley plugin for parsing 'multipart/form-data' bodies

Downloads

3

Readme

@medley/multipart

npm Version Build Status Coverage Status dependencies Status

A Medley plugin for parsing multipart/form-data request bodies, which are primarily used for uploading files. It is written on top of Busboy and inspired by multer.

Installation

# npm
npm install @medley/multipart

# yarn
yarn add @medley/multipart

Usage

Registering the plugin adds a .multipart() method to the app. This method creates a preHandler hook that will parse multipart/form-data bodies.

The hook will add a body and a files property to the req object if it completes successfully, where req.body will contain the text values of the form and req.files will contain the uploaded files.

If an error occurs, req.body and req.files will remain undefined.

Example:

<form action="/profile" method="post" enctype="multipart/form-data">
  <input type="text" name="firstName" />
  <input type="file" name="profilePhoto" />
</form>
const medley = require('@medley/medley');
const app = medley();

app.register(require('@medley/multipart'));

app.post('/profile', [
  app.multipart({
    profilePhoto: {maxCount: 1},
  }),
], (req, res, next) => {
  req.files.profilePhoto // The uploaded file (see File Object below)
  req.body.firstName // The user's first name
});

API

Plugin Options

| Option | Type | Description | Default | |--------|------|-------------|---------| | preservePath | boolean | If paths in the multipart 'filename' field shall be preserved. | false | | limits | object | Various limits on incoming data. Valid properties are: | | limits.fieldNameSize | integer | Max field name size (in bytes). | 100 | | limits.fieldSize | integer | Max field value size (in bytes). | 1 MiB | | limits.fields | integer | Max number of non-file fields. | Infinity | | limits.fileSize | integer | The max file size (in bytes). | Infinity | | limits.files | integer | The max number of file fields. | Infinity | | limits.parts | integer | The max number of parts (fields + files). | Infinity | | limits.headerPairs | integer | The max number of header key-value pairs to parse. | 2000 |

Specifying the limits can help protect your server against denial of service (DoS) attacks.

const medley = require('@medley/medley');
const app = medley();

app.register(require('@medley/multipart'), {
  limits: {
    fieldSize: 100 * 1024, // 100 KiB
    fileSize: 5 * 1024 * 1024, // 5 MiB
    files: 4,
  },
});

app.multipart(expectedFiles[, options])

| Option | Type | Description | |--------|------|-------------| | expectedFiles | object or 'ANY_FILES' | Required. An object mapping file field names to the maximum number of files expected for the field. See details below. | | options | object | The same as the global plugin option. Will be merged with the global plugin options (while taking precedence over them). |

The options parameter allows for route-specific control over upload limits.

app.multipart({
  profilePhoto: {maxCount: 1},
}, {
  limits: {
    fields: 1,
    fileSize: 8 * 1024 * 1024, // 8 MiB
  },
})

expectedFiles

Specifies the expected file fields and limits the number of files that can be received for those fields. If unexpected files are received, the upload will be cancelled with an error.

{
  fieldName: { maxCount: integer, optional?: boolean} | integer
}
app.multipart({
  someFile: {maxCount: 1},
  multipleFiles: {maxCount: 6},
  moreFiles: 5, // maxCount shorthand
})

Expected files are required by default, so an error will be thrown if an expected file is not uploaded. Set optional: true to allow the upload to complete without receiving any files for a particular field.

app.post('/upload', [
  app.multipart({
    requiredFile: {maxCount: 1},
    optionalFiles: {maxCount: 5, optional: true},
  }),
], (req, res, next) => {
  req.files.requiredFile // Will always exist
  req.files.optionalFiles // May be `undefined` or an array of files
});

The maxCount value determines the value type of the property in the req.files object. If maxCount is 1, the value will be a file object. If maxCount > 1, the value will be an array of file objects (even if only a single file is received).

app.post('/upload', [
  app.multipart({
    oneFile: {maxCount: 1},
    multipleFiles: {maxCount: 5},
  }),
], (req, res, next) => {
  req.files.oneFile // { ... }
  req.files.multipleFiles // [ { ... }, { ... }, { ... } ]
});

If expectedFiles is the special string 'ANY_FILES', any files may be uploaded and file objects will always be stored in an array. Note that the 'ANY_FILES' option should not be used in a production environment.

multipart.discardFiles(files)

Exported directly by the module, this method safely discards all of the files in the req.files object.

This is only needed when the multipart preHandler hook completes successfully but the files won't be handled (e.g. if an error happens).

const multipart = require('@medley/multipart');

// ...

// Something went wrong and the files need to be discarded
multipart.discardFiles(req.files);

multipart.MultipartError

The error constructor that this plugin uses to create errors when something goes wrong. It can be used to check if an error was generated by multipart inside an error handler.

const {MultipartError} = require('@medley/multipart');

app.setErrorHandler((err, req, res) => {
  if (err instanceof MultipartError) {
    // This is a multipart error
  }
});

See the code for the properties attached to MultipartError objects.

File Object

| Property | Description | |----------|-------------| | stream | fs.ReadStream of the file. | | fileName | The name of the file on the user's computer. An empty string ('') if no name was supplied by the client. | | mimeType | The MIME type of the file reported by the client using the Content-Type header. | | size | The size of the file in bytes. |

Note: The file stream must be handled in some way (even discarded by doing stream.destroy()) to ensure that the underlying file descriptor gets closed and the temporary file gets deleted.

app.post('/profile', [
  app.multipart({
    profilePhoto: {maxCount: 1},
  }),
], (req, res, next) => {
  const {profilePhoto} = req.files;

  profilePhoto.stream // ReadStream {}
  profilePhoto.fileName // 'me.jpg'
  profilePhoto.mimeType // 'image/jpeg'
  profilePhoto.size // 3483297
});

Error Handling

When encountering an error, multipart will delegate the error to Medley. Note that if multipart did not create the error, you may need to discard the uploaded files.

const multipart = require('@medley/multipart');

app.setErrorHandler((err, req, res) => {
  if (err instanceof multipart.MultipartError) {
    // This is a multipart error
  } else if (req.files !== undefined) {
    multipart.discardFiles(req.files);
  }
});