It may not be surprising that one has already uploaded a file today, whether it will disappear after a time or be stored in an online database. Thus, It has become imperative to create applications enabling file uploads. Using NextJs server-side, one can implement this.
This article is in two parts. In the first part, we discuss the frontend, where we will talk about what our project does and the tools needed. Then the second part is about implementing image and video uploads to Cloudinary and how to persist data in Xata Database.
What we are Building
The project is a digital flashcard for memorizing. A flashcard aids in learning what one wants to remember. A physical flashcard has a front and a back; the front usually poses a question, and the reverse usually offers the solution. A digital flashcard allows us to add images and videos to help us better remember an idea, code, nation's flag, etc.
The advantages of a flashcard are listed below.
- It aids in enhancing visual memory.
- They promote learning rate and are constantly portable.
- For acronyms, mathematical formulas, algorithmic codes, etc., flashcards are instructive.
- It is affordable.
See demo here
GitHub URL
https://github.com/Theodore-Kelechukwu-Onyejiaku/hackmamba-xata-cloudinary-project
Live DEMO
https://hackmamba-xata-cloudinary-project.vercel.app/
The Frontend
The frontend part of our work deals with how we interact with our project as seen in the live URL shared above. Here are the tools used for the frontend.
Frontend Tools
Using the npm i <tool_name>
command we can install them.
-
aos
: This is used for the animation of cards as we scroll down the application. -
react-icons
: this was used to display icons in our project. -
react-quill
: for the WYSIWYG editor for adding front and back content. -
react-toastify
: this was used for the toast notifications in our app. - Tailwind CSS: this is the main CSS of our application. Please note that other custom CSS was used in the project. Visit the Github URL above to see all.
Frontend Logic
Here is the logic of our application.
- A user registers by utilizing the Credentials or Github providers (email and password). Look at the file at 'pages/auth/signup' in the Github URL.
- After successful registration, the user is routed to the login page "pages/auth/signin."
- After successfully logging in, the user can view all of the cards that other users have made.
- We can choose from options like making a card, seeing our collections and cards, searching for a card based on its name or category, switching between dark and light settings, like a card, and watching a video.
- The card name, category, image, optional video, and front and back content must all be added before a card can be created.
- The user can begin flipping cards to practice memorizing, and films and visuals will assist them to develop their memory.
- A user who is the card's owner can update or delete the card once it has been created.
- A user can add a freshly made card to their collection by clicking the Plus symbol while they are not the owner of it.
- There are three options for editing a card. We have the option to only update the card's image, video, or other information.
- We can search for a card by typing its name or its category into the search box.
Below is a High-Level Model of the frontend logic:
Visit the live URL above to see the application.
The Backend
Cloudinary Installation and Configuration
1. Install Cloudinary
Run this command.
npm install cloudinary
2. Create a Cloudinary Account
We need our Cloudinary cloud name, API key, and API secret to proceed. Head over to the Cloudinary website here to get these three.
Click on the dashboard tab. There, we will find our API key, API secret, and cloud name.
Click on settings, then click on upload. There*,* you can be able to add presets.
Give the name and folder the value “flashcard” and click "save".
3. Add Cloudinary details to .env.local
file
Create a .env.local
file and add the following.
// .env.local
CLOUDINARY_API_KEY=<our_key>
CLOUDINARY_API_SECRET=<our_api_secret>
CLOUDINARY_NAME=<our_cloud_name>
4. Create Cloudinary Configuration file
Create a folder in the root of our project called utils
. Inside it, create a file cloudinary.js
and add the following code.
Xata Installation and Setup
1. Create a Xata account.
Click this link to create a Xata account.
2.Create Database and Tables
If we are new to Xata on creating tables, please read and visit these links https://xata.io/docs/intro/getting-started and https://xata.io/docs/quickstart/index. Now create a database called “test” or “flashcard”. After that, create the following tables:
Users Table
Cards Table
3. Install Xata Database
Watch the video here and see this installation documentation. Or,
- Install Xata CLI:
npm install -g @xata/cli
- Next, connect with Xata database:
xata auth login
We choose “ Create a new API key in browser” when our terminal prompts us. This opens a browser. We enter the name of our API key.
If successful, we will see this on the browser page.
A message “All set! you can now start using xata” will be displayed on our terminal.
- Initialize our project with Xata
xata init
We choose the following during the terminal prompts;
- Select existing database “test” or “flashcard”.
- Select “Generate Javascript code with ES modules” for “Do you want to use code generation in our project”.
- Type in “utils/xata” for “Choose the output file for the code generator”.
- Select “no” for “Do you want to generate the TypeScript declarations?”.
- For “Choose a default development branch (fallback branch)” select “main”.
- Lastly, for “Do you want to create a .gitignore file and ignore the .env file?, select “yes”.
Once done, we should see the message “You are all set!”
Make sure to select utils/xata
as where our Xata Codegen file will reside. If successful, our xata.js
file should look like this:
Uploading Images and Video
Since this will be done on the NextJs server side, the following packages are to be installed.
npm i bcrypt datauri multer next-auth next-connect
-
bcrypt
: this will help in authentication, hashing of passwords, and verification. -
datauri
: will help us convert parsed files(image and video) to base 64 encodings. -
multer
: will help us parse the request body. -
next-auth
: this will add authentication. - next-connect: this will help us add Multer as a middleware to a route handler.
Create a create-card.js
file
We have to create a card to upload an image and a video. So create a file called create-card.js
inside the api
folder of the pages
folder.
This will handle any POST request to /api/create-card
.. So, the frontend will send form data, including the image and video we want to upload.
-
Line 1: we import the package
next-connnect
. - Line 9: we create a new Xata instance.
-
Line 20: we apply the Multer middleware. The Multer middleware ensures that it parses any files using the
any()
method. And we store the image and video for each card inside the variablesimage
andvideo
in lines 30 and 31. -
Line 33: we create the
datauri/parser
instance to convert the parsed files to a base 64 encodings file. This way, we can upload the image and video generated in lines 40 and 47 to cloudinary. -
Line 36-40: here, we convert the parsed image file to a base 64 encoding for upload to Cloudinary. This is done using the
uploader.upload()
method of the Cloudinary SDK. Notice we passed in the upload presets,flashcards,
and an option{ resource_type: 'image' }
telling Cloudinary that this is an image we want to upload. This method returns a response, including the URL of the new Image created, which is stored in the database asimage
. -
Line 43-47: Same as Line 36-40. The only difference is this time, we tell Cloudinary that it is a video
{ resource_type: 'video' }
. -
Line 60-73: we create a new card by invoking the
create()
function of Xata and passing the values from the frontend.
See what will be sent from the frontend in lines 115-126 below.
Updating an Existing Image
Updating an existing image in Cloudinary also means updating our card. Create a new API route handler called update-card-image.js
.
There is not much difference from create-card.js
.
-
Line 17: we told Multer that it should parse a single file named
image
. This is the name of the form data image from the frontend. -
Line 37: we delete the existing Cloudinary image of a card by invoking the Cloudinary
destroy()
method. This method only requires the id of the image to delete. - Line 43: we update the card with the new image URL, id, and signature.
Updating an Existing Video
This is the same as the code above. We will create a new file called update-card-video
. The only difference is that this time we tell Multer to parse a file named “video” in line 17. See the code below:
Deleting Images and Videos
In deleting a card, we thereby delete the image and video.
-
Line 21 and 26: we call the Cloudinary
destroy()
methods and passed the image id and video id of the card we want to delete. -
Line 30: we invoke the
delete()
method of Xata by passing the id of the card we want to delete.
Live Demo
https://hackmamba-xata-cloudinary-project.vercel.app/
Conclusion
In this article, we looked at uploading images and videos to Cloudinary using NextJs Server Side and persisting data in the database using Xata. The frontend and full code have been provided in the GitHub URL section of this article. Once again, visit here for the live application.