How to Upload and Manage Pictures on your Website (using Cloudinary API)

·

0 min read

download.png

Ever thought of making a website or web app that supports uploading and managing pictures but don’t know how to? I certainly have, and thankfully, there is an easy way to do just that. Although in order to properly benefit from this tutorial, there are a few things that you should know including the basics of server-side (back-end) programming and how HTTP requests work.

Setting Up The Front-End

For the purposes of this quick tutorial, the UI will just be a simple one with only one function: uploading pictures. I've built it using React, although vanilla JS, HTML, and CSS would work just fine.

Capture.PNG

Note that only two HTML elements are actually needed to make this initial UI.

<input name="image" type="file" />
<button><span>Upload</span></button>

Although, an additional p element for logging purposes (e.g., image is uploading, image has been successfully uploaded, error: image could not be added) is helpful and informative for any user.

The rest of the design for the front-end is arbitrary and eventually depends on the nature of your web app.

Setting Up the Back-End and Cloudinary API

Go ahead and sign up here for an account. It's completely free. Next, set up the back-end. I'll be using NodeJS (Express) and MongoDB (With Mongoose) for the database.

/* server.js */
const express = require('express');
const app = express();

// Setting up Mongo and Mongoose
const mongoose = require('mongoose')

/* Connnect to our database */
const mongoURI = process.env.MONGODB_URI || "mongodb://localhost:27017/ImageAPI"

mongoose.connect(mongoURI, { useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true });

Now, let's create a Mongoose model for an Image object and export it to server.js.

/* image.js */
const mongoose = require('mongoose');

// create an image schema
const imageSchema = mongoose.Schema({
    image_id: {
        type: String,
        required: true
    },
    image_url: {
        type: String,
        required: true
    },
    created_at: String
});

// create an image model using the schema
const Image = mongoose.model('Image', imageSchema);

module.exports = { Image };

Next, import the multipart middleware. This middleware basically allows you to access uploaded files from req.file.

const multipart = require('connect-multiparty');
const multipartMiddleware = multipart();

Finally, set up Cloudinary using your credentials which can be found on your Cloudinary dashboard.

const cloudinary = require('cloudinary');
cloudinary.config({
    cloud_name: 'REPLACE_WITH_CLOUD_NAME_HERE',
    api_key: 'REPLACE_WITH_API_KEY_HERE',
    api_secret: 'REPLACE_WITH_API_SECRET_HERE'
});

Building the API Routes

POST route to create an image

app.post("/images", multipartMiddleware, (req, res) => {

    // Use uploader.upload API to upload image to cloudinary server.
    cloudinary.uploader.upload(
        req.files.file.path, // req.files contains uploaded files
        function (result) {

            // Create a new image using the Image mongoose model
            const img = new Image({
                image_id: result.public_id, // image id on cloudinary server
                image_url: result.url, // image url on cloudinary server
                created_at: new Date(),
            });

            // Save image to the database
            img.save().then(
                saveRes => {
                    res.send(saveRes);
                },
                error => {
                    res.status(400).send(error); // 400 for bad request
                }
            );
        });
});

GET route to get all images

app.get("/images", (req, res) => {
    Image.find().then(
        images => {
            res.send({ images }); // can wrap in object if want to add more properties
        },
        error => {
            res.status(500).send(error); // server error
        }
    );
});

GET route to get an image by its database id

app.get("/images", (req, res) => {
    const query = {_id: req.query.id}
    Image.findOne(query).then(image => {
        if (!image) {
            res.status(404).send();  // could not find this img
        } else {
            res.send(image);
        }
    }).catch((error) => {
        res.status(500).send()  // server error
    })
});

A DELETE route to remove an image by its cloudinary id

app.delete("/images/:imageId", (req, res) => {
    const imageId = req.params.imageId;

    // Delete an image by its id (NOT the database ID, but its id on the cloudinary server)
    // on the cloudinary server
    cloudinary.uploader.destroy(imageId, function (result) {

        // Delete the image from the database
        Image.findOneAndRemove({ image_id: imageId })
            .then(img => {
                if (!img) {
                    res.status(404).send();
                } else {
                    res.send(img);
                }
            })
            .catch(error => {
                res.status(500).send(); // server error, could not delete.
            });
    });
});

Wrapping Up

To wrap up, we finalize server.js by setting our static directory, default routing, and where our server is listening.

app.use(express.static(__dirname + "/build"));

// All routes other than above will go to index.html
app.get("*", (req, res) => {
    res.sendFile(__dirname + "/build/index.html");
});

const port = process.env.PORT || 3000
app.listen(port, () => {
    log(`Listening on port ${port}...`)
})

And now, we are ready to send HTTP requests to create, fetch, and delete images through POST, GET, and DELETE requests from the front-end!

For example, to create an image, we can send a request like so:

const url = "/images";

const request = new Request(url, {
    method: "post",
    body: newImage, /* the image selected from the file input */
});

// Send the request with fetch()
fetch(request)
    .then(function (res) {
        if (res.status === 200) {
            console.log("Image was successfully uploaded")
        } else {
            console.log("Error: Could not upload image.")
        }
    })
    .catch(error => {
        console.log(error);
    });

For those who have made it this far, congrats! Especially to those of you who are new to this. I've been there before and it's definitely not easy to grasp it the first time.