Cloudinary and Postgresql - Persisting and Retrieving Images Using Nodejs
NJOKU SAMSON EBERE
Posted on April 28, 2020
In a previous article, we saw how we can upload images to Cloudinary using nodejs. It is however not so useful as we are not able to easily retrieve it especially when we want to use it in a project. In this article, we will be looking at how we can persist and retrieve images using postgres.
If you have not used postgres before, I suggest you start here. We are not using any ORM library so we will write our own queries.
At this point, I want to say a big Congratulations for getting up to this stage.
The next stage is to create database and a table. If you want to skip it to creating APIs, clone this repo. Let's Proceed.
Create Database and Table
So we want to start by cloning the previous project if you don't already have it here.
In your pgAdmin
Create a database and name it: tutorial
Create a table and name it: tutorial
Create a Login/Group Role and name it: tutorial. (Do not forget to give it all privileges)
Back in your project directory, install the node-postgres (npm install pg --save) and make-runnnable (npm install make-runnable --save) packages
In package.json file, replace the content of the "scripts" with "create": "node ./services/dbConnect createTables". This will be used to execute the dbConnect file we are about to create.
Create a services/dbConnect file to contain the following code
constpg=require("pg");constconfig={user:"tutorial",database:"tutorial",password:"tutorial",port:5432,max:10,// max number of clients in the poolidleTimeoutMillis:30000,};constpool=newpg.Pool(config);pool.on("connect",()=>{console.log("connected to the Database");});constcreateTables=()=>{constimageTable=`CREATE TABLE IF NOT EXISTS
images(
id SERIAL PRIMARY KEY,
title VARCHAR(128) NOT NULL,
cloudinary_id VARCHAR(128) NOT NULL,
image_url VARCHAR(128) NOT NULL
)`;pool.query(imageTable).then((res)=>{console.log(res);pool.end();}).catch((err)=>{console.log(err);pool.end();});};pool.on("remove",()=>{console.log("client removed");process.exit(0);});//export pool and createTables to be accessible from an where within the applicationmodule.exports={createTables,pool,};require("make-runnable");
Now we are all set to create the table in our database. If you are ready, let's rock and roll!
Execute the following code in your terminal
npmruncreate
If the image below is your result, then you are good to go
Check Your pgAdmin, and you should have your table seated properly in your database like in the image below
Wow!!! It's been a long road! It's time to unite Nodejs, Postgres and Cloudinary!
Create 2 APIs
API 1: Persist Image
Require the dbConnect.js file on the top of the app.js file like so:
constdb=require('services/dbConnect.js');
In the app.js file, make a new API (persist-image) with the following code:
// persist imageapp.post("/persist-image",(request,response)=>{// collected image from a userconstdata={title:request.body.title,image:request.body.image,}// upload image herecloudinary.uploader.upload(data.image).then().catch((error)=>{response.status(500).send({message:"failure",error,});});})
Replace the then block with the following code:
.then((image)=>{db.pool.connect((err,client)=>{// inset query to run if the upload to cloudinary is successfulconstinsertQuery='INSERT INTO images (title, cloudinary_id, image_url)
VALUES($1,$2,$3) RETURNING *';constvalues=[data.title,image.public_id,image.secure_url];})})
If you have gone through the prerequisite to this tutorial, then you should know where we are getting result.public_id and result.secure_url. If you didn't follow, please go through this tutorial
Still in the then block, add the following code under the query we created
// persist imageapp.post("/persist-image",(request,response)=>{// collected image from a userconstdata={title:request.body.title,image:request.body.image}// upload image herecloudinary.uploader.upload(data.image).then((image)=>{db.pool.connect((err,client)=>{// inset query to run if the upload to cloudinary is successfulconstinsertQuery='INSERT INTO images (title, cloudinary_id, image_url)
VALUES($1,$2,$3) RETURNING *';constvalues=[data.title,image.public_id,image.secure_url];// execute queryclient.query(insertQuery,values).then((result)=>{result=result.rows[0];// send success responseresponse.status(201).send({status:"success",data:{message:"Image Uploaded Successfully",title:result.title,cloudinary_id:result.cloudinary_id,image_url:result.image_url,},})}).catch((e)=>{response.status(500).send({message:"failure",e,});})})}).catch((error)=>{response.status(500).send({message:"failure",error,});});});
Now let's test out all our hard works
Open your postman and test out your API like the image below. Mine was successful. Hope yours had no errors too?
Open your cloudinary console/dashboard and check your media Library. Your new Image should be seating there comfortably like mine below:
And Now to the main reason why we are here, check the images table in your pgAdmin. Mine is what you see below
Uhlala!!! We made it this far! Please take a break if you need one. I will be here waiting when you return.
If you are ready, then let's retrieve the image we persisted a moment ago
Next, we will need to collect a unique ID from the user to retrieve a particular image. So add const { id } = request.params; to the code above like so:
app.get("/retrieve-image/:cloudinary_id",(request,response)=>{// data from userconst{cloudinary_id}=request.params;});
Add the following below the code above
db.pool.connect((err,client)=>{// query to find imageconstquery="SELECT * FROM images WHERE cloudinary_id = $1";constvalue=[cloudinary_id];});
Under the query, execute the query with the following code
// execute queryclient.query(query,value).then((output)=>{response.status(200).send({status:"success",data:{id:output.rows[0].cloudinary_id,title:output.rows[0].title,url:output.rows[0].image_url,},});}).catch((error)=>{response.status(401).send({status:"failure",data:{message:"could not retrieve record!",error,},});});
Now our retrieve-image API looks like this:
app.get("/retrieve-image/:cloudinary_id",(request,response)=>{// data from userconst{cloudinary_id}=request.params;db.pool.connect((err,client)=>{// query to find imageconstquery="SELECT * FROM images WHERE cloudinary_id = $1";constvalue=[cloudinary_id];// execute queryclient.query(query,value).then((output)=>{response.status(200).send({status:"success",data:{id:output.rows[0].cloudinary_id,title:output.rows[0].title,url:output.rows[0].image_url,},});}).catch((error)=>{response.status(401).send({status:"failure",data:{message:"could not retrieve record!",error,},});});});});
Let's see how well we did
In your postman, copy the "cloudinary_id" and add it to the URL like in the image below
YEEESSS!!! We can also retrieve our image!
If you are here, then you deserve a round of applause and a standing ovation for your industriousness.
Congratulations! You just reached a great milestone.
Conclusion
It has been a beautiful session with you as we started out by creating a database and table in our pgAdmin after which we proceeded to create an API to upload our image to cloudinary and create a record of it in our database. Finally, we created an API to retrieve our record from our database.