Tutorial: File Uploads

File Uploads

Overview

flitter-upload provides a simple, middleware-based file upload system for Flitter. This allows files to be uploaded, stored, and categorized seamlessly. This is done with the hope of reducing the hassle of keeping track of and serving uploaded files. Here, we'll build a sample picture uploader to take a look at how to use flitter-upload.

Step 0: Deploy Flitter Upload

Flitter upload provides a basic configuration file and upload middleware that we need to enable for the application. To do this, we'll use the upload deployment:

./flitter deploy upload

This creates the app/routing/middleware/upload/UploadFile.middleware.js and config/upload.config.js files.

Configuration

Flitter Upload supports multiple file storage backends. These are configured in the config/upload.config.js file. You must set a default provider name in the file. This is the provider used by the middleware to upload files, however you can have multiple backends configured.

Step 1: Create the basic upload form and routes.

Now, we're going to create a basic upload form and endpoint to get a feel for Flitter Upload. This is by no means the only way to use this library, but it is the most common, and should give you a good feel for its capabilities.

Create views/upload.pug:

html
    body
        form(method='post' enctype='multipart/form-data')
            input(type='file' name='img' required)
            button(type='submit') Upload

Create the route in app/routing/routers/index.routes.js:

get: {
    '/': [ 'controller::Home.welcome' ],
    '/upload': [ 'controller::Home.get_upload' ],
},

Create the controller function in app/controllers/Home.controller.js:

get_upload(req, res){
    return res.page('upload')
}

Step 2: Create the upload submission route.

Now, we're going to create the POST endpoint used by the form to submit the files.

Create the route in app/routing/routers/index.routes.js:

post: {
    '/upload': [ 'middleware::upload:UploadFile', 'controller::Home.post_upload' ],
},

Here, we invoke the upload:UploadFile middleware that was created when we ran the upload deployment before passing off control to the post_upload method on the Home.controller.js. This middleware uploads the files included in the request (in our case, the file uploaded in the img field) to the configured default store, then inserts the instances of module:flitter-upload/model/File~File that it created into request.uploads by name.

So, we can access the the img file through request.uploads.img.

Step 3: Add the controller method.

Let's send a basic response to let the user know that their file was uploaded successfully. Add the following to app/controllers/Home.controller.js:

post_upload(req, res){
    const img_file = req.uploads.img

    // original_name and id are properties of the flitter-upload/model/File model.
    res.send(`File ${img_file.original_name} uploaded with ID ${img_file.id}.`)
}

Step 4: Add the retrieval route.

Now, let's create a route users can use to download their files. The user will navigate to the route, providing the store_id from the File model, and out controller will send the file as a response. Create the route in app/routing/routers/index.routes.js:

get: {
    '/': [ 'controller::Home.welcome' ],
    '/upload': [ 'controller::Home.get_upload' ],
    '/file/:id' : [ 'controller::Home.get_file' ],
},

Add the handler function in app/controllers/Home.controller.js (note that the controller must import the models service):

async get_file(req, res, next) {
  const File = this.models.get('upload::File')
  const file = await File.findById(req.params.id)

  if ( !file ) return res.error(404, {message: 'File not found with that ID.'})

  // Call the send() method on the File model. This sends the file through the passed-in response.
  else return file.send(res)
}

Now, if it is found, the file with the given ID will be served to the user. Here, we find the instance of the module:flitter-upload/model/File~File model with the given ID. Flitter Upload handles setting the response's Content-Type and Content-Disposition headers automatically to match the originally uploaded file.