# File Uploader Plugin

Note: XpresserJs also supports all express supported file handling libraries.

Built on busboy (opens new window), an easy plugin to handle file uploads from form request to your application storage folder.

# Installation

# NPM

npm install @xpresser/file-uploader

# YARN

yarn add @xpresser/file-uploader

# Add to plugins.json

Add npm://@xpresser/file-uploader to your plugins.json, if you don't have one create a new one in your backend folder.

# Typescript

Add the code below to your xpresser.d.ts file.

import "@xpresser/file-uploader/xpresser";

# Single File Upload

In your view


<form action="/upload" enctype="multipart/form-data" method="POST">
  <input type="file" name="avatar"/>
  <input type="submit" value="Upload  your avatar"/>
</form>

In your controller action

$.router.post('/upload', async (http) => {
  
  // Get File
  const file = await http.file('avatar', {
    size: 1, // 1MB
    mimeType: "image",
    extensions: ["png", "jpg", "gif"],
  });
  
  // Check for error
  if (file.error()) {
    return http.res.send(file.error())
  }
  
  // Save File
  await file.saveTo('path/to/folder');
  
  // check for save error()
  if (!file.isSaved()) {
    return http.res.send(file.saveError());
  }
  
  // return response.
  return http.res.send({
    file: file,
    msg: "File uploaded successfully!."
  });
});

# Multiple Files Upload

In your view


<form action="/multiple_upload" enctype="multipart/form-data" method="POST">
  Select images: <input type="file" accept="image/*" name="images" multiple>
  <button type="submit">Upload your images</button>
</form>

In your controller action

$.router.post('/multiple_upload', async (http) => {
  // Get Files
  const images = await http.files('images', {
    files: 10,
    size: 1,
    mimetype: 'image'
  });
  
  // check errors
  if (images.hasFilesWithErrors()) {
    const filesWithErrors = images.filesWithError();
    
    // Do something with filesWithErrors
    
    return http.send({
      message: 'Upload encountered some errors'
    })
  }
  
  // Save all files to one folder
  await images.saveFiles('path/to/folder');
  
  // Or save files to specific folder using conditions by passing a function
  await images.saveFiles((file) => {
    return 'path/to/images/' + file.extension();
  });
  
  // return response
  return http.send({
    message: `${images.files.length} files has been uploaded successfully!.`
  });
});

# Form Body

The body of the form is returned by http.file and http.files function

const image = http.file('fieldname');
console.log(image.body)

// OR

const files = http.files(['fieldname1', 'fieldname2']);
console.log(files.body)

# Configuration Options

http.file & http.files have different but similar configuration options.

# size

To limit file/files size, you can set maximum file size in megabytes using the size config option.

const file = await http.file("fieldName", {
  size: 1 // 1 megabyte
});

# mimetype

The mimetype config restricts uploads to a specific mimetype and can either be a string or a regular expression.

const image = await http.file("avatar", {
  mimetype: "image" // string
});

const images = await http.files("images", {
  mimetype: new RegExp("png|jpg|gif") // Regex
});

# extensions

To allow only certain extensions, you can pass them as an array of strings.

const logo = await http.file("logo", {
  extensions: ["png", "svg"]
});

const docs = await http.files("documents", {
  extensions: ['pdf', 'doc', 'docx', 'txt']
});

# includeBody

If for some reasons you want to exclude the body of the request set IncludeBody to false. Note: This is enabled by default.

const logo = await http.file("logo", {includeBody: false});

# mimetypeForEachField (files)

The mimetypeForEachField config enables you to define specific mimetype for each fieldName like so:

const files = await http.files(["logos", "attachments"], {
  mimetypeForEachField: {
    logos: "image",
    attachments: new RegExp("(image|pdf|audio)")
  }
});

Files uploaded with fieldName attachments will fail if the mimetype does not match either image, pdf or audio.

# extensionsForEachField (files)

The extensionsForEachField config enables you to define specific extensions for each fieldName like so:

const files = await http.files(["logos", "attachments"], {
  extensionsForEachField: {
    logos: ["png", "svg"],
    attachments: ["jpg", "pdf", "audio"]
  }
});

Files uploaded with fieldName attachments will fail if the extension does not match either jpg, pdf or audio.

# UploadedFile (class)

The UploadedFile class is returned when a single file is uploaded.

# Properties

Property Type Description
input string Name of the input field.
name string Name of the uploaded file.
path string? Path to saved file.
tmpPath string Path to file's temporary location.
encoding string Encoding of the uploaded file.
mimetype string Mimetype of the uploaded file.
size number Size of uploaded file in bytes.
body object The body of the request.

# error()

This method checks if the current file has an error. If there is no error, it returns false else it returns an object of the type below.

interface FileError {
    type: "input" | "file" | "size" | "mimetype" | "extension";
    message: string;
    expected?: string;
    received?: string;
}

const file = await http.file("png");

if (file.error()) {
    return file.error().message;
}

Note: Error is cached and only computed once per request. So calling file.error() multiple times refers to the same cached value.

# nameWithoutExtension()

Return the file name i.e file.name without its extension.

const file = await http.file("avatar", {
    extensions: ["png", "jpg"]
});

// Assuming file name is
// photo-image.2022.03.01.png

console.log(file.nameWithoutExtension()); // "photo-image.2022.03.01"

# extension()

Returns the extension of the uploaded file

const file = await http.file("document", {
    extensions: ["pdf"]
});

console.log(file.extension()); // "pdf"

# dotExtension()

Same function as file.extension() but is prefixed with dot '.'

console.log(file.dotExtension()); // ".pdf"

# extensionMatch()

Checks if file extension matches the string provided or is included array provided.

const file = await http.file("document", {
  extensions: ["pdf"]
});

console.log(file.extensionMatch("jpg")); // false
console.log(file.extensionMatch(["pdf", "jpg"])); // true

# dotExtensionMatch()

Same function as file.extensionMatch() but with dot '.' prefixed.

const file = await http.file("document", {
  extensions: ["pdf"]
});

console.log(file.dotExtensionMatch(".jpg")); // false
console.log(file.dotExtensionMatch([".pdf", ".jpg"])); // true

# sizeToString()

This method returns string representation of the file.size value.

Sizes: ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]

file.sizeToString() // 30KB

# saveTo()

Save uploaded file to storage folder provided.

const file = await http.file("document", {
  extensions: ["pdf"]
});

// Save to folder.
await file.saveTo("full/path/to/storage", {
  name: "optional-filename",
  overwrite: true,
  prependExtension: false,
});

# OPTIONS

  • name: Filename, if not defined, original file name will be used.
  • overwrite: Default: true, if set to false an error will be thrown if the file already exists.
  • prependExtension: Default: false, if set to true, the file's extension will be added to filename

# isSaved()

This function checks if an uploaded file is saved to the folder specified when using file.saveTo().

// Save to folder.
await file.saveTo("full/path/to/storage", {
  name: "optional-filename",
  overwrite: true,
  prependExtension: false,
});

if (file.isSaved()) {
  // Maybe store path to db
  await Db.create(file.path)
}

# saveError()

This method checks returns the file.saveTo() error if any.

// Save File
await file.saveTo('path/to/folder');

// check for save error()
if (!file.isSaved()) {
  return http.res.send(file.saveError());
}

# discard()

Should in any case you no longer want to save uploaded file. You can discard it.
This function will try to delete the uploaded file from the temporary location where it is stored.

# UploadedFiles (class)

The UploadedFile class is returned when multiple files are uploaded.

# Properties

Property Type Description
input string Name of the input field, (Each file will also have its own input)
body object The body of the request.
files UploadedFile[] Array of uploaded files.

# saveFiles()

This method loops through files without error and saves them to the path provided.

Note: It expects same arguments as UploadedFile's saveTo() method.

const files = await http.files(["images", "docs"]);

await files.saveFiles("path/to/folder", {overwrite: true})

# Providing specific paths for each file.

To provide specific path or options for each file, pass a function to both arguments. This function will be called during the loop and the current looped file will be passed as an argument.

const files = await http.files(["images", "docs"]);

await files.saveFiles(
    file => `uploads/${file.extension()}`,
    file => ({overwrite: file.input === 'images'})
)

Using the example above, pdf files will be saved to uploads/pdf and other extensions will be saved to their respective folders as well.

# hasFiles()

Checks if there are any uploaded files. Returns boolean

files.hasFiles()
// Is equivalent to
files.files.length > 0

# hasFilesWithErrors()

Checks if any uploaded file has Error. Returns boolean

const files = await http.files(["images", "docs"]);

if (files.hasFilesWithErrors()) {
  // do something
}

# hasFilesWithoutErrors()

Checks if uploaded files has any file without Error. Returns boolean

const files = await http.files(["images", "docs"]);

if (files.hasFilesWithoutErrors()) {
  // do something
}

# filesWithError()

Returns an array of uploaded files with Error.

const files = await http.files(["images", "docs"]);

// loop files
files.filesWithError().forEach(file => {
  // log error message
  console.log(file.error().message)
})

# filesWithoutError()

Returns an array of uploaded files without Error.

const files = await http.files(["images", "docs"]);

// loop files
for (const file of files.filesWithoutError()) {
  // Save file.
  await file.saveTo(`uploads/${file.extension()}`)
}