Skip to main content
Version: v2

File Upload and Download

In version 2, file uploads and download are managed by a single package: @foal/storage.

The @foal/formidable Package

This package has been removed. Use @ValidateMultipartFormDataBody hook instead.

npm uninstall formidable @foal/formidable @types/formidable
npm install @foal/storage
settings:
disk:
driver: 'local'
local:
directory: 'uploaded'

Before

export class AppController {

@Post('/upload')
async upload(ctx: Context) {
const form = new IncomingForm();
form.uploadDir = 'uploaded';
form.keepExtensions = true;
const { fields, files } = await parseForm(form, ctx);

console.log(files.file1);
// {
// "size": 14911887,
// "path": "uploaded/upload_de9cb95c.pdf",
// "name": "example.pdf",
// "type": "application/pdf",
// "mtime": "2019-03-25T13:58:27.988Z"
// }

// ...
}

}

After

import { ValidateMultipartFormDataBody } from '@foal/storage';

export class AppController {

@Post('/upload')
@ValidateMultipartFormDataBody({
files: {
file1: { required: true, saveTo: '.' },
}
})
async upload(ctx: Context) {
const { fields, files } = ctx.request.body;

console.log(files.file1);
// {
// "path": "de9cb95cde9cb95cde9cb95c.pdf",
// "filename": "example.pdf"
// "mimeType": "application/pdf",
// }

// ...
}

}

Warning: the file path generated by @ValidateMultipartFormDataBody does not start with uploaded/. If you save your file paths in your database, you will need to update them to remove this at the beginning (for example using a shell script).

The createHttpResponseFile Function

The function createHttpResponseFile in @foal/core has been removed. Use Disk.createHttpResponseFile hook instead.

npm install @foal/storage
settings:
disk:
driver: 'local'
local:
directory: 'uploaded'

Before

class AppController {

@Get('/download')
download() {
return createHttpResponseFile({
directory: 'uploaded/',
file: 'my-pdf.pdf'
});
}

}

After

import { Disk } from '@foal/storage';

class AppController {

@dependency
disk: Disk;

@Get('/download')
download() {
return this.disk.createHttpResponse('my-pdf.pdf');
}

}

Usage with Buffers

If you use @ValidateMultipartFormDataBody with buffers, update your code as follows:

// Before
const buffer = ctx.request.body.files.foobar;

// After
const { buffer } = ctx.request.body.files.foobar;

The AbstractDisk/Disk Service

If you extend the abstract class AbstractDisk, you must add a readSize method which returns the size of the file.

AbstractDisk has been renamed to Disk.

New features

Accessing File Metadata

When uploading files, the browser sends additional metadata. This can be accessed in version 2 in the controller method.

const file = ctx.request.body.files.profile;
// file.mimeType, ...
Property nameTypeDescription
encodingstringEncoding type of the file
filenamestring|undefinedName of the file on the user's computer
mimeTypestringMime type of the file
pathstringPath where the file has been saved. If the saveTo option was not provided, the value is an empty string.
bufferBufferBuffer containing the entire file. If the saveTo option was provided, the value is an empty buffer.