How to Upload and Delete Images Using Cloudinary API with Nextjs
Image and asset management services like Cloudinary offer comprehensive features for the automatic optimization and transformation of images. Yet, in the realm of website development, it is unrealistic to expect that each user will manually upload images using your dashboard. How can you enable your users to effortlessly upload their own images directly from your website?
Certainly! When dealing with your hosting server, it's advisable to steer clear of directly uploading images. This is mainly due to limitations in storage capacity and the potential for optimization problems. Instead, opt for image and asset management services like Cloudinary. These platforms are designed for efficient handling of image uploads.
Getting Started: How to Upload and Delete Images Using Cloudinary API with Nextjs
1. Creating Your Cloudinary Account
To begin the integration process, make sure to set up an free account on the Cloudinary website. Sign up and acquire your API key, API secret, and cloud name for a seamless experience.
2. Creating a new Next.js app
3. Install Cloudinary Package
In your Next.js project, install the Cloudinary package using the following command:
npm install cloudinary sha1
4. Setup Upload Preset Name:
When we upload media to Cloudinary, we can choose between two methods: signed and unsigned.
By signing our requests, we ensure that any uploaded content is authenticated, and we can verify the uploader's permission.
Alternatively, unsigned requests provide broader access for users trying to upload images to our site.
In this guide, we'll focus on unsigned requests. The key is to configure an Upload Preset, informing Cloudinary how to manage uploads linked to that specific preset.
To create the Upload Preset, navigate to the Cloudinary dashboard, click the Settings, and choose the Upload tab.
You can generate an additional preset by selecting "Add upload preset."
In the "Add upload preset" section, you will encounter three options:
Upload Preset Name:
- Choose any name you prefer. I'll name mine "upload_images."
Signing Mode:
- Since we're opting for Unsigned Uploads, select "Unsigned."
Folder:
- While using a folder is optional, it's advisable, especially during testing. It provides an organized way to manage uploads. I'll label my folder "uploadimages."
5. Configure Environment Variables:
Set up your environment variables in the .env.local file with the Cloudinary credentials:
NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME=your_cloud_name
NEXT_PUBLIC_CLOUDINARY_API_KEY=your_api_key
NEXT_PUBLIC_CLOUDINARY_API_SECRET=your_api_secret
NEXT_PUBLIC_CLOUDINARY_PRESET_NAME=your_upload_preset_name
6. Building UploadImages Function:
const fileInputRef = useRef(null);
const [images, setImages] = useState([]);
const [isUploading, setIsUploading] = useState(false);
async function uploadImages(ev) {
const files = ev.target?.files;
if (files?.length > 0) {
setIsUploading(true);
let data = new FormData();
for (const file of files) {
data.append("file", file);
data.append(
"upload_preset",
process.env.NEXT_PUBLIC_CLOUDINARY_PRESET_NAME
);
}
const res = await fetch(`/api/upload`, {
method: "POST",
body: data,
});
const imageResponse = await res.json();
if (imageResponse.status === 200) {
setImages((prev) => {
return [...prev, imageResponse.uploadedImageData];
});
}
setIsUploading(false);
}
}
Let's break down the key components of the uploadImages
function:
- The function is an asynchronous event handler, accepting an event (
ev
) as a parameter. It checks if there are files attached to the event, proceeding if there are. - The function sets a state variable,
setIsUploading
, totrue
to indicate that the image upload process is in progress. - A
FormData
object, nameddata
, is created to construct the body of the HTTP request. It iterates through each file, appending it to thedata
object along with an upload preset value. - Using the Fetch API, the function sends a POST request to the
/api/upload
endpoint with the constructedFormData
object as the request body. - The function awaits the server response, parses it as JSON, and if the response status is 200 (OK), it updates the state variable
setImages
with the newly uploaded image data. - Finally, the
setIsUploading
state variable is set back tofalse
to signify the completion of the image upload process.
7. Building Cloudinary API Route For Uploading Images:
import { NextResponse } from "next/server";
export async function POST(req) {
try {
const formData = await req.formData();
const img = formData.get("file");
if (!img) {
return NextResponse.json({ success: false, message: "no image found" });
}
const uploadResponse = await fetch(
`https://api.cloudinary.com/v1_1/${process.env.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME}/image/upload`,
{
method: "POST",
body: formData,
}
);
const uploadedImageData = await uploadResponse.json();
return NextResponse.json({
uploadedImageData,
message: "Success",
status: 200,
});
} catch (error) {
return NextResponse.json({ message: "Error", status: 500 });
}
}
Let's break down the key components of the cloudinary api route for uploading images
function:
- The function uses
await req.formData()
to asynchronously retrieve the FormData object from the incoming request (req
). This FormData object is expected to contain the uploaded image file. - It checks if the FormData object contains an element with the name "file" (representing the uploaded image). If not, it returns a JSON response indicating the absence of an image.
- The code uses the Fetch API to send a POST request to the Cloudinary API endpoint for image uploads. The
process.env.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME
is used to dynamically construct the Cloudinary cloud name based on the environment configuration. - After uploading, it asynchronously parses the response from Cloudinary as JSON. This response typically contains information about the uploaded image, such as its public URL and other metadata.
- Finally, it returns a JSON response to the client, including the Cloudinary image data, a success message, and a status code of 200.
- In case of any errors during the process, it catches the errors and returns a JSON response indicating an error with a status code of 500.
8. Building DeleteImages Function:
async function deleteImage(url) {
const res = await fetch(`/api/upload/?url=${url}`, {
method: "DELETE",
});
const deletedImageData = await res.json();
if (deletedImageData.status === 200) {
setImages((prev) => {
return prev.filter((elem) => elem.secure_url !== url);
});
}
fileInputRef.current.value = ""; // Reset the file input value
}
Let's break down the key components of the deleteimages
function:
- The function uses the Fetch API to send a DELETE request to the
/api/upload
endpoint with the specified image URL as a query parameter. - It asynchronously parses the response from the server as JSON. The response likely contains information about the success or failure of the deletion.
- If the deletion was successful (status code 200), it updates the state by removing the deleted image from the
images
array. ThesetImages
function is assumed to be a state-setting function from a React context or component. - It resets the value of the file input field, assuming that
fileInputRef
is a reference to the file input element. This ensures that after deleting an image, the file input is cleared.
9. Building Cloudinary API Route For Deleting Images:
import sha1 from "sha1";
export async function DELETE(req) {
try {
const { searchParams } = new URL(req.url);
const url = searchParams.get("url");
if (!url) {
return NextResponse.json({ success: false, message: "no url found" });
}
const regex = /\/upload\/v\d+\/(uploadimages\/[^.]+)\.\w{3,4}$/;
const publicId = url.match(regex);
const timestamp = new Date().getTime();
const string = `public_id=${publicId[1]}×tamp=${timestamp}${process.env.NEXT_PUBLIC_CLOUDINARY_API_SECRET}`;
const signature = sha1(string);
const formData = new FormData();
formData.append("public_id", publicId[1]);
formData.append("signature", signature);
formData.append("api_key", process.env.NEXT_PUBLIC_CLOUDINARY_API_KEY);
formData.append("timestamp", timestamp);
const res = await fetch(
`https://api.cloudinary.com/v1_1/${process.env.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME}/image/destroy`,
{
method: "POST",
body: formData,
}
);
await res.json();
return NextResponse.json({
message: "Success",
status: 200,
});
} catch (error) {
return NextResponse.json({ message: "Error", status: 500 });
}
}
Let's break down the key components of the cloudinary api route for deleting images function:
- The
sha1
function is commonly used for generating SHA-1 hashes. SHA-1 (Secure Hash Algorithm 1) is a cryptographic hash function that produces a fixed-size 160-bit hash value. - It extracts the 'url' parameter from the request URL using the URLSearchParams API.
- Checks if the 'url' parameter is missing then returns a JSON response with an error message.
- Then uses a regular expression to extract the public ID from the Cloudinary URL and generates a timestamp. Then, it creates a string for signature generation and computes the signature using SHA-1 hashing.
- Then creates a FormData object with the necessary parameters for the request body.
- Then sends a POST request to Cloudinary's image destroy endpoint with the generated FormData object.
- Then parses the response from Cloudinary as JSON, although the result is not used in this code snippet.
- If the process is successful, it returns a JSON response indicating success with a status code of 200. If there's an error, it returns a JSON response indicating an error with a status code of 500.
In this blog, we looked at uploading and deleting images using Cloudinary API with Nextjs.
For full code you can visit Github url:
https://github.com/webrishprojects/uploadimages-cloudinary
Thank you for taking the time to read the blog. If you have any questions, feel free to ask in the comment section. Explore my Portfolio for additional projects, blogs and content that I have uploaded.
Comments
Post a Comment