@medley/multipart

    0.3.0 • Public • Published

    @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);
      }
    });

    Install

    npm i @medley/multipart

    DownloadsWeekly Downloads

    6

    Version

    0.3.0

    License

    MIT

    Unpacked Size

    21.7 kB

    Total Files

    7

    Last publish

    Collaborators

    • avatar