We have learnt to create most of features of an Ecommerce website. Still, we are missing one very major function of the web which is Image uploading. Any product should have Image to better identified and attract customers.
The basic process of our uploading Image feature are :
Cloudinary is a cloud service that offers a solution to a web application's entire image management pipeline.
Easily upload images to the cloud. Automatically perform smart image resizing, cropping and conversion without installing any complex software. Integrate Facebook or Twitter profile image extraction in a snap, in any dimension and style to match your website's graphics requirements. Images are seamlessly delivered through a fast CDN, and much much more.
For Node.js, Cloudinary provides an extension for simplifying the integration even further.
.env
:npm install cloudinary
We are ready to start using cloudinary
Multer is a node.js middleware for handling multipart/form-data, which is primarily used for uploading files. .
NOTE: Multer will not process any form which is not multipart (multipart/form-data).
Multer adds a body object and a file or files object to the request object. The body object contains the values of the text fields of the form, the file or files object contains the files uploaded via the form.
Since the client could send any files to our server, we will need to filter out any files that not images. To do that, we will use file.extname : extention as an indicator of file type.
const multer = require("multer");
const path = require("path");
module.exports=multer({
storage:multer.diskStorage({})
fileFilter:(req,file,cb)=>{
let ext=path.extname(file.originalName)
if(ext !==".jpg"&&ext!==".jpeg"&&ext!=="png"){
cb(new Error("File extension not supported"),false)
return
}
cb(null,true)
}
})
What isfaker
? faker
is a JavaScript tool that helps generate realistic fake data for your applications. Their documentations are lacking so we will go over some common situations you may run into in this lecture, from very simple to moderately complex.
First, install faker
in your backend project:
npm install faker
Create a new file called generateData.js
in the root of your project. We will run this file independently of the backend when we want to generate data.
In this file, import faker
:
const faker = require('faker');
Instead of writing our own function to generate a random number from a predefined range with Math.random()
, faker
has its own function that we can utilize.
Let's write a function to generate a random number from 0 and 10. We will use the namespace random
from faker
, and we want a number, so we will use faker.random.number()
:
const getRandomNumber = () => {
const num = faker.random.number(10)
}
The default min
is 0 and this .number()
method takes a number argument as the max value. You can also pass an object with min
and max
here.
For example, if you want a random number between 22 and 50, you can do:
const num = faker.random.number(28) + 22;
or
const num = faker.random.number({min: 22, max: 50})
Previously, in order to get a random item in an array, we needed to do something like:
const arr = ["apple", "watermelon", "peach"];
const randomIndex = Math.floor(Math.random()*arr.length);
const randomElement = arr[randomIndex];
If you want more than 1 item, it will be even more complicated. Now faker
has something similar already which can save you a lot of time if you have many arrays to work with.
faker.random.arrayElement(array)
: For this, we need to pass an array to this function. It will return a random item in that array.
const arr = ["apple", "watermelon", "peach"];
const randomElement = faker.random.arrayElement(arr);
faker.random.arrayElements(array, num)
: This function will return multiple non-repeating items inside an array. Therefore we need to pass the array itself and a number which represents how many items we want back from this array.
const arr = ["apple", "watermelon", "peach"];
const randomElement = faker.random.arrayElements(arr, 2);
// this will return 2 random items in the array arr
We mostly use these methods to generate gibberish long texts. For example, for product reviews, product details, blog posts, post titles, About Us text, etc.
faker.lorem.words(number)
: We pass in a number to generate that exact number of random lorem words.
const randomWords = faker.lorem.words(3);
// example result: iure quos aut
faker.lorem.paragraphs(number)
: We pass in a number to generate a number of paragraphs.
const randomParagraphs = faker.lorem.paragraphs(3);
/** example result:
Dolorem excepturi aut id esse neque. Voluptate corrupti ducimus fuga fugit. Itaque ex libero rerum porro. Reprehenderit omnis quis dolorum numquam quia ducimus est molestias. Sed non et voluptas explicabo iure voluptatem. Aut minus ut dolorem unde.
Ipsa molestiae enim neque culpa sit corporis cum. In odio aut. Est aperiam facere esse itaque omnis. Et alias doloribus.
**/
We will use various faker
namespaces to generate a semi-complete user profile data. Let's go over the most basic user information.
Name:
We can use faker.name.findName()
to generate a full name (that may include a title). You can also customize it further to return a female name or a male name, or a fixed first name or last name. The function has 3 optional parameters: first name, last name and gender.
const randomName1 = faker.name.findName();
//will return a random full name
const randomName2 = faker.name.findName('', '', 0);
// will return a random male name (0 = male, 1 = female)
// will possibly return something like Ms. Luke Klein even though gender = male because the title is not considered
If your user schema has a gender field and you want the name to match this field, you may need to combine several different faker
functions together:
const gender = 0; //male
const firstName = faker.name.firstName(gender);
const lastName = faker.name.lastName();
const fullName = firstName + " " + lastName;
Email:
We can use faker.internet.email()
to get a completely random email, or we can pass firstName
and/or lastName
as an argument to this to get a more personal email:
const gender = faker.random.number(1); //male or female
const firstName = faker.name.firstName(gender);
const lastName = faker.name.lastName();
const fullName = firstName + ' ' + lastName;
const email = faker.internet.email(firstName, lastName);
console.log(fullName);
console.log(email);
// example result
//Edward Volkman
//Edward_Volkman@gmail.com
You can also generate an address, a date of birth (faker.date.betweens
), etc. Just experiment with some of the namespaces until you're familiar with faker
.
Let's say you need a name, a description, some categories and a price for your product. We can't really use a person's name for the product's name. Furthermore, while a lorem ipsum text would work for the description, faker
provides something better with its commerce
namespace.
faker.commerce.productName()
: As the name suggests, this will return a product-eque name. The name may sound funny or ridiculous, but that's okay because we're not trying to pass this as a real product.
const randomName = faker.commerce.productName();
// example result: Incredible Rubber Computer
faker.commerce.productDescription()
: Will return some nonsensical description, which is better than a lorem ipsum text, but if you want control over the length of the description, then faker.lorem
is the better choice.
const randomDesc = faker.commerce.productDescription();
// example result:
// The slim & simple Maple Gaming Keyboard from Dev Byte comes with a sleek body and 7- Color RGB LED Back-lighting for smart functionality
faker.commerce.department()
: This is to generate the category for your product. If you want multiple categories, simply run it in a for loop.
const category = faker.commerce.department();
// example result: Beauty
faker
also has a price
function, but if you're working with VND where the smallest denomination is 500 (or 1000 in reality), then it doesn't make sense to generate a number like 529163. You can use a trick for this with the normal faker.random.number()
.
const randomPrice = faker.random.number({min: 50, max: 3000}) * 1000;
// price ranging from 50000 to 3000000
Combine all of this together, you can have a nice looking product object:
{
name: "Incredible Rubber Computer",
description: "The slim & simple Maple Gaming Keyboard from Dev Byte comes with a sleek body and 7- Color RGB LED Back-lighting for smart functionality",
categories: ["Beauty", "Home"]
price: 630000,
}
faker
has an image namespace as well, but it's not good, so let's ignore it for now.
Now that we can generate some data in Node.JS, we need to actually get this data onto our database. Just like with your backend project, we can connect to our MongoDB in Node.JS using mongoose
:
require('dotenv').config();
const mongoose = require('mongoose');
const mongoURI = process.env.MONGODB_URI;
mongoose
.connect(mongoURI, {
// some options to deal with deprecated warning
useCreateIndex: true,
useNewUrlParser: true,
useFindAndModify: false,
useUnifiedTopology: true,
})
.then(() => {
console.log(`Mongoose connected to ${mongoURI}`);
})
.catch((err) => console.log(err));
Then let's create an async function to generate 20 users. We're going to need to import our User
schema before we can do anything with MongoDB.
const User = require('./models/User');
//...
const generateUser = async (num) => {
for (let i = 0; i < num; i++) {
const user = await User.create({
name: faker.name.findName(),
email: faker.internet.email(),
// you may need to hash this password first
password: "123",
});
console.log(`User ${i+1} ${user.name} created!`)
}
}
Now run it at the bottom:
generateUser(10);
You should see the results in both your terminal and your MongoDB database. You can apply a similar logic to create data for Product
, Comment
,Rating
, Cart
(transactions), and more. Of course it won't be this simple, but with practice, you'll figure out how to handle the relationships between these models.
Since the image generator of faker
is frustratingly lackluster, we need to rely on an extra service to handle generating random images. Unsplash is one of them. However, their random image API (and their database) will return artistic, scenic images while what we need are product images. Therefore we will need to find the images that fit your theme yourself.
If you have download enough of them I don't want to manually upload them to Cloudinary, write down the URLs and save them to your database, then you can automate this process with the help of Cloudinary Upload API and faker
.
You can find the documentation here.
cloudinary
package:npm install cloudinary
generateData.js
, include cloudinary
from the package we just installed: cloudinary = require('cloudinary').v2;
cloudinary.config({
cloud_name: 'YOUR_CLOUD_NAME',
api_key: 'YOUR_API_KEY',
api_secret: 'YOUR_API_SECRET'
});
cloudinary.uploader.upload("YOUR_LOCAL_IMAGE_PATH", function(error, result) {console.log(result, error)});
This is a single file update. should we repeat this every time we want to generate image data?
We can't possibly do the previous step over and over again for every single image we have. That would not be different from manually uploading the images using Cloudinary widget.
That's why we need to put all the images we want to upload in a folder, and get all of the image file's names and put them in an array, then we can loop through the array and upload them, or upload random elements of the array.
images
. This folder and our generateData.js
file should be on the same level (they should be in the same folder) for easy navigation.fs.readdirSync()
to read all the files in a folder. This will return an array of all the file names.let images = fs.readdirSync('./images');
//console.log() it to be sure
console.log(images)
Whenever you create a new product, you need to get a random file name from this images
array, then upload that file to Cloudinary and save the URL in the response to your database.
const generateProduct = async (num) => {
for (let i = 0; i < num; i++) {
const product = await Product.create({
name: faker.commerce.productName(),
price: faker.random.number({min: 50, max: 3000}) * 1000,
images: [image]
});
console.log(`User ${i+1} ${product.name} created!`)
}
}
Combining this with the previous steps, you should be able to upload random images and attach the response's links to your products, then save them in your database.
create
cart then also pay
for it that have random amount of items choose, random unique
items choose and random amount of quatity (quatity request could be invalid). Eg : user A has 1 cart that have 3 random unique
items , each of them have random qty of request. Also , user B has 1 cart that have 10 random unique
items , each of them have random qty of request.Case 1 : Create a cart , then pay for it, but product is out of stock Res 1 : Cart still active, move on to next user Case 2 : Create a cart, then pay for it, but current balance is insufficient Res 2 : Cart still active, move on to next user Case 3 : Create a cart, then pay for it, and everything is good Res 3 : Cart is PAID, current user balance is Deducted, Product stock is deducted.