Preamble
AdonisJs documentation shows how to upload files to the server using the HTML5 <form> element. But there are cases where axios comes more handy. So let us see how to upload files from a Nuxt.js client application to an AdonisJS RESTful API server with axios. I shared this project on my Github profile.
Project setup
In my demo, the client and server code are set apart. My client application is handled by Nuxt.js:
|
|
and the server by AdonisJs:
|
|
On my Github project, I use Vuetify.js and Eslint.
Nuxt.js client code
Here is where the main code is located:
|
|
And this is the simple user interface I want to create:

Basically I like to have MainPage.vue component to wrap all my other components; in this case I need only the FileUpload.vue component:
|
|
The essential part of the code is what the FileUpload.vue component contains. So I show here the full code and then will explain the main points:
1<template>
2 <v-container
3 grid-list-md
4 text-xs-center
5 fill-height>
6 <v-layout
7 row
8 wrap
9 align-center>
10 <v-flex
11 xs6
12 offset-xs3>
13 <v-text-field
14 v-model="photoName"
15 name="photo"
16 outline
17 background-color="blue"
18 color="blue"
19 label="Select image"
20 append-icon="attach_file"
21 @click="selectImage"/>
22 <input
23 ref="image"
24 class="hide-input"
25 type="file"
26 accept="image/*"
27 @change="imageSelected">
28 <v-btn
29 class="upload-button"
30 color="indigo"
31 @click="upload_photo">
32 Upload
33 <v-icon
34 right
35 color="white">
36 cloud_upload
37 </v-icon>
38 </v-btn>
39 </v-flex>
40 </v-layout>
41 </v-container>
42</template>
43
44<script>
45export default {
46 name: 'FileUpload',
47 data: () =>({
48 photo: '',
49 photoName: ''
50 }),
51 methods: {
52 selectImage() {
53 this.photo = this.$refs.image.click()
54 },
55 imageSelected(e) {
56 this.$emit('input', e.target.files[0])
57 this.photo = this.$refs.image.files[0]
58 this.photoName = this.photo.name
59 },
60 async upload_photo() {
61 let formData = new FormData()
62 formData.append('file', this.photo)
63 let url = 'http://127.0.0.1:3333/upload'
64 let config = {
65 headers: {
66 'content-type': 'multipart/form-data'
67 }
68 }
69 await this.$axios({
70 method: 'post',
71 url: url,
72 data: formData,
73 config: config
74 })
75
76 }
77 }
78}
79</script>
80
81<style scoped>
82.hide-input {
83 display: none;
84}
85*{
86 text-transform: none !important;
87}
88.upload-button {
89 border-radius: 50px;
90 color: white;
91}
92</style><input> element, I need to hide this later one when displaying the <v-text-field /> component. This is the traditional simple but efficient trick usually used in this case; then we trigger a click on this hidden file input as follows:
|
|
My input file element is referenced with image, that is why we need to look to the references available in this DOM template with it:
|
|
In my particular case, I am interested in uploading images only, that is why I set accept="image/*". The main thing not to forget in the AJAX request is to declare the content-type header. I think the rest of the code is self explanatory:
|
|
If you are a one-liner, the asynchronous code above (the await part) can be written concisely as follows:
|
|
AdonisJs REST API server code
On the server, I first set the endpoint in start/routes.js:
|
|
Then I created the corresponding controller:
|
|
Inside this controller (app/Controllers/Http/PhotoController.js), I received the object File() sent by the axios POST request in my client code by inspecting the request object of AdonisJs: const photo = request.file('file'). Note that I use file to reference its key in the FormData() object which contains it. Below I rename the file with the current time of the server’s machine:
|
|
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.