loading...

Image or File Uploads in Adonis.js with Cloudinary

massivebrains profile image Massive brains ・3 min read

I just started working with adonis JS a little over 2 months now. I recently have to use Cloudinary in my project and i searched for the best way to loosely use it so as to maintain the readable, expressive and approachable structure of Adonis.

This tutorial assumes you are already familiar with Adonis and Cloudinary. I will explain my approach in steps below. So let's get Started!

Step 1: Create a new AdonisJS project

Run

adonis new cloudinary-integration

to create a new adonis project. You should get a fresh adonis project (as at the writing of this post, i'm using version 4.1)

Step 2: Setup an upload controller

Create a new HTTP controller by running

adonis make:controller Upload --type http

and setup a simple index method as shown below


'use strict'

class UploadController {

    async index ({ request, response }) {

        return response.json({status: true, data: 'It Works '})
    }
}

module.exports = UploadController

And of cause update the /start/routes.js by adding a new route

'use strict'

const Route = use('Route')

Route.on('/').render('welcome')

//Add this Route
Route.get('/upload', 'UploadController.index')

Step 3: Implementing Cloudinary

At this point, if you do not have a cloudinary account, head over to https://cloudinary.com to create a free account. We would need three major environment variables from cloudinary.

  • CLOUDINARY_CLOUD_NAME
  • CLOUDINARY_API_KEY
  • CLOUDINARY_API_SECRET

Update your .env file to have these three environment variables. See Screenshot below on where to get them from your cloudinary console.

So your .env file will now look somewhat like this

HOST=127.0.0.1
PORT=3333
NODE_ENV=development
APP_URL=http://${HOST}:${PORT}
CACHE_VIEWS=false
APP_KEY=iBRP92LhBPRKh0rTIcIo2OuyQNbWCY6C
DB_CONNECTION=sqlite
DB_HOST=127.0.0.1
DB_PORT=3306
DB_USER=root
DB_PASSWORD=
DB_DATABASE=adonis
SESSION_DRIVER=cookie
HASH_DRIVER=bcrypt

#Cloudinary Credentials
CLOUDINARY_CLOUD_NAME=your_cloudinary_cloud_name
CLOUDINARY_API_KEY=your_cloudinary_api_key
CLOUDINARY_API_SECRET=your_cloudinary_api_secret

Next, Let's pull in the cloudinary JS SDK from npm (or yarn).

npm i cloudinary --save

Then, create a file /app/Services/Cloudinary.js with the following code snippet.

'use strict'

const cloudinary = use('cloudinary')
const Env = use('Env')

cloudinary.config({

    cloud_name: Env.get('CLOUDINARY_CLOUD_NAME'),
    api_key: Env.get('CLOUDINARY_API_KEY'),
    api_secret: Env.get('CLOUDINARY_API_SECRET'),
})

module.exports = {

    upload: async (file) => {

        return new Promise(async (resolve, reject) => {

            try{

                let response = await cloudinary.uploader.upload(file.tmpPath, { folder: 'test'})

                resolve({status: true, url: response.secure_url })

            }catch(error){

                reject({status: false, url: error.message })
            }
        })
    }
}

We are returning a promise from an async function called upload which we would be passing a file object to.

Step 4: Using the cloudinary Service

Now that we have our Cloudinary service setup. lets create a method in our app/Http/Controllers/UploadController.js to handle uploads.

Our UploadController.js will now look like this

'use strict'

//Import Cloudinary
const Cloudinary = use('App/Services/Cloudinary')

class UploadController {

    async index ({ request, response }) {

        return response.json({status: true, data: 'It Works '})
    }

    async upload ({ request, response }) {

        //TODO: Validate. Input.

        try{

            if(request.file('image')){

                let cloudinary_response = await Cloudinary.upload(request.file('image'))

                return response.json(cloudinary_response)
            }

            return response.json({status: false, data: 'Please upload an Image.'})

        }catch(error){

            //console.log(error)
            return response.status(500).json({status: false, error: error.message })
        }

    }
}

module.exports = UploadController

one more thing, lets add a route to our new method. Our routes file will now look like so

'use strict'

const Route = use('Route')

Route.on('/').render('welcome')

//Add this Route
Route.get('/upload', 'UploadController.index')
Route.post('/upload', 'UploadController.upload')

Step 5: Testing from Postman

For the purpose of testing, we do not want to use the CSRF protection for now. So in your /config/shield.js Update the csrf key as below so has to exclude the /upload route

csrf: {
    enable: true,
    methods: ['POST', 'PUT', 'DELETE'],
    filterUris: ['/upload'],
    cookieOptions: {
      httpOnly: false,
      sameSite: true,
      path: '/',
      maxAge: 7200
    }
  }

Now to test our upload route and be sure our implementation is working as expected. Try uploading a file from postman as shown below

You should be able to see your newly uploaded file from your cloudinary media library.

That's all folks!

Discussion

pic
Editor guide