[IBM LoopBack 101] API File Upload and Download Support

As a Distributed Systems 2020–21 Class project, in this article we will create a API called FileTransferAPI using the IBM LoopBack 4 that will allow us to upload and download files.

Having the Visual Studio Code installed on a Windows 7 machine, we will start the VSCode and on the left of the window, on the explorer, we will create a new folder named FileTransferApi.

Right-click again on the folder explorer item and click Open in Integrated Terminal (and choose as New Command Prompt in the dropdown menu).

Navigate to the FileTransferApi folder early created, and if you never have installed the LoopBack 4 CLI toolkit, execute the following command to install it:

Note: For any error, try run the VSCode as Administrator.

npm i -g @loopback/cli

To initialize our application using the LoopBack 4 CLI toolkit, we going to execute multiple commands on the terminal and fill the asked fields (when showed ‘(something)’, the something it’s usually the advised/example value).

Note: Pay attention on the following pictures to know witch answer was used/selected.

lb4 app

Now, let’s create a controller class such as FileUploadController. After navigating into the project folder, execute the following command and follow the instructions of the image below:

lb4 controller

Before we put some code into the file-upload.controller.ts, we will inject an instance of FileUploadService, as this one is configurable to support various storage engines, and is backed by multer to process the incoming http request.

“Multer is a node.js middleware for handling multipart/form-data, which is primarily used for uploading files. Multer adds a body object and a file or files object to the request object. The body object contains the values of the text fields of the form, the file or files object contains the files uploaded via the form.” — https://github.com/expressjs/multer

So, we will execute the following command to install mulder as a development dependency:

npm i --save-dev @types/multer

Development Dependency: is any package that absence will not affect the work of the application. In package.json file under the devDependencies section contains the list of all development dependencies. When someone installs your package they will not install any development dependencies but if they clone the repository, then they will install all the development dependencies too.

[ File Upload ]

Now in the src directory, we will create 2 files (types.ts and keys.ts)and 1 directory (services) with 2 files into (index.ts and file-upload.service.ts).

In the src directory, create a new file named types.ts with the code:

import {RequestHandler} from 'express-serve-static-core';export type FileUploadHandler = RequestHandler;

Again, in src directory, create a second file named keys.ts with the code:

import {BindingKey} from '@loopback/core';
import {FileUploadHandler} from './types';
// Binding key for the file upload service
export const FILE_UPLOAD_SERVICE =
BindingKey.create<FileUploadHandler>('services.FileUpload',);
// Binding key for the storage directory
export const STORAGE_DIRECTORY = BindingKey.create<string>
('storage.directory');

Inside the src directory, create a new folder named services, and inside of it, create the following two files with the respective codes:

export * from './file-upload.service';

Returning to the early controller created, put the following code into it:

To finalize this part, let’s make some changes into the application.ts by adding code as showed below:

...
} from '@loopback/rest-explorer';
import multer from 'multer'; <- This
...
import path from 'path';
import{FILE_UPLOAD_SERVICE,STORAGE_DIRECTORY} from './keys'; <- This
...
export class FileTransferApiApplication extends BootMixin(
ServiceMixin(RepositoryMixin(RestApplication)),
) {
constructor(options: ApplicationConfig = {}) {
...
this.component(RestExplorerComponent);
// Configure file upload with multer options
this.configureFileUpload(options.fileStorageDirectory); <- This
...
}
And at the final of the FileTransferApiApplication class, put:
protected configureFileUpload(destination?: string) {
// Upload files to `dist/.sandbox` by default
destination = destination ?? path.join(__dirname, '../.sandbox');
this.bind(STORAGE_DIRECTORY).to(destination);
const multerOptions: multer.Options = {
storage: multer.diskStorage({
destination,
// Use the original file name as is
filename: (req, file, cb) => {
cb(null, file.originalname);
},
}),
};
// Configure the file upload service with multer options
this.configure(FILE_UPLOAD_SERVICE).to(multerOptions);
}
}

[ File Download ]

As the File Upload, now let’s create a controller for the File Download, as showed in the picture below:

And add the following code:

And now, let’s start the server and using a browser, go to localhost:3000/explorer/ to test our API.

npm start

To test the upload, on the FileUploadController, go to POST/files and Try it out by Choosing a File from your computer and Execute.

After executing some more POST’s, and if we go to the FileDownloadController, we can try to do a GET/files to see all the files that have been uploaded:

In the FileDownloadController we also can download each file, to do that, we only need to make a GET/files/{filename} and Try it out by input the file name with the respective extension and click Download file at the Server Response body. Let’s try with the FileTransferAPI-ExplorerPicture.png file:

As showed above, our API is working as intended but let’s make it more appealing. So, we will add some new controls into index html page of the API.

In the public directory in the index.html, replace the code with the code below as this one as the new code (and old) to add a new section for file upload and download using scripts.

As we can see, our API is working as intended.

Hope you liked this small article, best regards, Ricardo Costa (Richards).

This article was created in a context of the Distributed Systems Class 2020–21, ESTG-IPG.