The majority of upload libraries/frameworks process files multiple times when streaming to an external service such as Amazon S3. Their upload workflows are usually designed like so:
Process request files then save them to the tmp directory.
Move each file from the tmp directory to the destination directory.
Use the external service’s SDK to finally stream the file to the external service.
This process wastes server resources reading/writing single files multiple times.
That is what you can read on the official AdonisJs documentation. Here we learn how to implement that by streaming the files directly to the MySQL database.
Our stack
AdonisJs: to build the RESTful API server
Nuxt.js + Vuetify: to design a user interface to interact with our API.
Our app
And this is the simple user interface I want to create:
The left button will be used to upload a file to the RESTful API server. The right button will be used to download it and display it on the right side
Project setup
In my demo, the client and server code are set apart. My client application is handled by Nuxt.js:
1
yarn create nuxt-app client
and the server by AdonisJs:
adonis new server --api-only
On my Github project, I use Vuetify.js and Eslint.
Let us break down this mess. Most the above code was explained in the previous article. We added two small aspects to it though. First, we display the image we choose to send to the server. This image preview functionality in Nuxt.js can be useful in many cases you are enough smart to guess. For that, we draw some place holders in the form of Vuetify components to show it up when it is ready:
As we can see, the image will be displayed only if url is loaded v-if="url". This famous url is just a variable we declared in the data() method, and we set its content to point to the local photo selected by the user using: URL.createObjectURL(this.photo).
We also added a Vuetify component to display the photo sent back by the server on a button click:
We set photoId to 1 in loadPhotoFromServer() because we are interested to display the file which ID equals to 1 in the MySQL database. We use $axios.defaults.baseURL to refer to the baseURL key we defined in nuxt.config.js file to point to the URL on which our AdonisJs API is being served:
Note that Knex.js which is used by AdonisJs here, does not have a predefined data field for images apart from binary. Luckily this same Knex.js offers us the possibility to define a data type of our choice as long as the RDBMS we use supports it using knex.specifiType() method to define the longblob table column.
Since are not interested in using the timestamps fields for our photos table, we should inform the corresponding model Photo.js about it:
We used the store() method in the previous article. Here we only add the show() method which receives the photoId we mentioned previously as a paramter in order to use to fetch for the photo in the MySQL database. Of course, as for uploading the photo, we need to define the headers properly to let the client know which type of data it is going to handle.
We can use either the Database or the Query Builder providers to look for the photo in the database. Our code comments out the previous option so that we can use each one we prefer.
If you upload a photo, you will find it on the server, precisely in the folder /tmp/photos. Note that you have to enable CORS for the requests to be acceped. You can do that by setting cors: true in config/cors.js file. For larger images, set the limit value of maxSize to whatever you want in /config/bodyParser.js which is 20mb by default.
Note that we forgot to mention one important thing. Actually it is the first thing to set in the API because without it/them we can not communicate with the server: the routes. So in start/routes.js, we can define the routes to our photos resources as follows:
1
Route.resource('photos','PhotoController')
That is it. I made a GitHub repository for this demo if anyone wants to try it or make a pull request to improve it.