/E-commerce-api

an e-commerce backend built with node js.

Primary LanguageJavaScript

Hosted Project

E-Commerce API Heroku URL

Setup Basic Express Server

  • [] import express and assign to variable
  • [] setup start port variable (5000) and start function

Connect To DB

  • [] get connection string
  • [] setup .env with MONGO_URL variable and assign the value
  • [] import 'dotenv' and setup package
  • [] import connect() and invoke in the starter
  • [] restart the server
  • [] mongoose V6 info

Basic Routes and Middleware

  • [] setup / GET Route
  • [] setup express.json() middleware
  • [] setup 404 and errorHandler middleware
  • [] import 'exress-async-errors' package

404 vs ErrorHandler Middleware

Morgan Pacakge

User Model

  • [] create models folder and User.js file
  • [] create schema with name,email, password (all type:String)
  • [] export mongoose model

Validator Package

Auth Routes Structure

  • [] create controllers folder
  • [] add authController file
  • [] export (register,login,logout) functions
  • [] res.send('some string value')
  • [] create routes folder
  • [] setup authRoutes file
  • [] import all controllers
  • [] setup three routes
  • [] post('/register') post('/login') get('/logout')
  • [] import authRoutes as authRouter in the app.js
  • [] setup app.use('/api/v1/auth', authRouter)

Test Routes in Postman

Register Controller

  • [] create user
  • [] send response with entire user (only while testing)
  • [] check if email already in use (schema and controller)
  • [] ignore 'role'
  • [] alternative 'admin' setup

Handle Password

  • [] UserSchema.pre('save') - hook
  • this points to User
  • bcrypt.genSalt - number of rounds
  • bcrypt.hash

JWT

  • [] require 'jsonwebtoken' package
  • [] create jwt - jwt.sign(payload,secret,options)
  • [] verify jwt - jwt.verify(token,secret)
  • [] add variables in .env JWT_SECRET=jwtSecret and JWT_LIFETIME=1d
  • [] restart the server !!!!
  • [] refactor code, create jwt functions in utils
  • [] refactor cookie code
  • [] setup func attachCookiesToResponse
  • [] accept payload(res, tokenUser)
  • [] create token, setup cookie
  • [] optionally send back the response

Login Route

  • [] check if email and password exist, if one missing return 400
  • [] find user, if no user return 401
  • [] check password, if does not match return 401
  • [] if everything is correct, attach cookie and send back the same response as in register

Logout Route

  • [] set token cookie equal to some string value
  • [] set expires:new Date(Date.now())

User Routes Structure

  • [] add userController file
  • [] export (getAllUsers,getSingleUser,showCurrentUser,updateUser,updateUserPassword) functions
  • [] res.send('some string value')
  • [] setup userRoutes file
  • [] import all controllers
  • [] setup just one route - router.route('/').get(getAllUsers);
  • [] import userRoutes as userRouter in the app.js
  • [] setup app.use('/api/v1/users', userRouter)

GetAllUsers and GetSingleUser

  • [] Get all users where role is 'user' and remove password
  • [] Get Single User where id matches id param and remove password
  • [] If no user 404

Authenticate User Setup

Auth User Complete

Authorize Permissions Setup

  • [] hardcode

Authorize Permissions Complete

  • [] introduce params

ShowCurrentUser

  • [] get user from req
  • [] send response with user

UpdateUserPassword

  • [] almost identical to login user
  • [] add authenticateUser middleware in the route
  • [] check for oldPassword and newPassword in the body
  • [] if one missing 400
  • [] look for user with req.user.userId
  • [] check if oldPassword matches with user.comparePassword
  • [] if no match 401
  • [] if everything good set user.password equal to newPassword
  • [] await user.save()

createTokenUser in Utils

  • [] create a file in utils (createTokenUser)
  • [] setup a function that accepts user object and returns userToken object
  • [] export as default
  • [] setup all the correct imports/exports and refactor existing code

updateUser with User.findOneAndUpdate()

  • [] add authenticateUser middleware in the route
  • [] check for name and email in the body
  • [] if one is missing, send 400 (optional)
  • [] use findOneAndUpdate()
  • [] create token user, attachCookiesToResponse and send back the tokenUser

updateUser with user.save()

Setup and Apply checkPermissions()

Product Model

  • [] create Product.js in models folder
  • [] create Schema
  • [] name : {type:String}
  • [] price: {type:Number}
  • [] description: {type:String}
  • [] image: {type:String}
  • [] category: {type:String}
  • [] company: {type:String}
  • [] colors: {type:[]}
  • [] featured: {type:Boolean}
  • [] freeShipping: {type:Boolean}
  • [] inventory:{type:Number}
  • [] averageRating:{type:Number}
  • [] user
  • [] set timestamps
  • [] export Product model

Product Structure

  • [] add productController file in controllers
  • [] export (createProduct, getAllProducts, getSingleProduct, updateProduct, deleteProduct, uploadImage) functions
  • [] res.send('function name')
  • [] setup productRoutes file in routes
  • [] import all controllers
  • [] only getAllProducts and getSingleProduct accessible to public
  • [] rest only by admin (setup middlewares)
  • [] typical setup
  • [] router.route('/uploadImage').post(uploadImage)
  • [] import productRoutes as productRouter in the app.js
  • [] setup app.use('/api/v1/products', productRouter)

Product Routes in Postman

Create Product

  • [] create user property on req.body and set it equal to userId (req.user)
  • [] pass req.body into Product.create
  • [] send back the product

Remaining Controllers (apart from uploadImage)

  • [] getAllProducts
  • [] getSingleProduct
  • [] updateProduct
  • [] deleteProduct
  • [] typical CRUD, utilize (task or job) project
  • [] remember we check already for role 'admin'

Upload Image

  • [] if some question, re-watch 07-file-upload
  • [] images folder with two images

Review Model

  • [] create Review.js in models folder
  • [] create Schema
  • [] rating : {type:Number}
  • [] title: {type:String}
  • [] comment: {type:String}
  • [] user
  • [] product
  • [] set timestamps
  • [] export Review model

Review Structure

  • [] add reviewController file in controllers
  • [] export (createReview, getAllReviews, getSingleReview, updateReview, deleteReview) functions
  • [] res.send('function name')
  • [] setup reviewRoutes file in routes
  • [] import all controllers
  • [] only getAllReviews and getSingleReview accessible to public
  • [] rest only to users (setup middleware)
  • [] typical REST setup
  • [] import reviewRoutes as reviewRouter in the app.js
  • [] setup app.use('/api/v1/reviews', reviewRouter)

Create Review

  • [] check for product in the req.body
  • [] attach user property (set it equal to req.user.userId) on to req.body
  • [] create review
  • [] don't test yet

Get All Reviews and Get Single Review

  • [] both public routes, typical setup

Delete Review

  • [] get id from req.params
  • [] check if review exists
  • [] if no review, 404
  • [] check permissions (req.user, review.user)
  • [] use await review.remove()
  • [] send back 200

Update Review

  • [] get id from req.params
  • [] get {rating, title comment} from req.body
  • [] check if review exists
  • [] if no review, 404
  • [] check permissions
  • [] set review properties equal to rating, title, comment
  • [] use await review.save()
  • [] send back 200

Populate

Virtuals

Get Single Product Reviews

Remove All Reviews

Aggregation Pipeline - Atlas and Code

Order Schema

  • [] create Order.js in models folder
  • [] create Schema
  • [] tax : {type:Number}
  • [] shippingFee: {type:Number}
  • [] subtotal: {type:Number}
  • [] total: {type:Number}
  • [] orderItems:[]
  • [] status:{type:String}
  • [] user
  • [] clientSecret:{type:String}
  • [] paymentId:{type:String}
  • [] set timestamps
  • [] export Order model

Order Structure

  • [] add orderController file in controllers
  • [] export (getAllOrders, getSingleOrder, getCurrentUserOrders, createOrder, updateOrder) functions
  • [] res.send('function name')
  • [] setup orderRoutes file in routes
  • [] import all controllers
  • [] authenticate user in all routes
  • [] getAllOrders admin only
  • [] typical REST setup
  • [] router.route('/showAllMyOrders').get(getCurrentUserOrders)
  • [] import orderRoutes as orderRouter in the app.js
  • [] setup app.use('/api/v1/orders', orderRouter)

Order in Postman

Create Order

  • [] most complex

Get All Orders and Get Single Order

  • [] getAllOrders - admin only
  • [] getSingleOrder - chechPermissions

Get Current User Orders

  • [] find orders where user is equal to req.user.userId

Update Order

  • [] get order id
  • [] get paymentIntentId (req.body)
  • [] get order
  • [] if does not exist - 404
  • [] check permissions
  • [] set paymentIntentId and status as 'paid'
  • [] order.save()

Create Docs

Security Packages

  • [] express-rate-limiter
  • [] helmet
  • [] xss-clean
  • [] express-mongo-sanitize
  • [] cors (cookies!!!!)

Deploy on Heroku

  • [] heroku account and heroku cli
  • [] remove/copy from the main repo
  • [] add dev command "nodemon app.js"
  • [] change start to "node app.js"
  • [] setup node version in package.json
  • [] "engines": {"node": "14.x"}
  • [] Procfile "web: node app.js"
  • [] remove existing git repo
  • [] rm -rf .git - mac,
  • [] git init
  • [] git add .
  • [] git commit -m "initial commit"
  • [] heroku login
  • [] heroku create "App Name"
  • [] git remote -v
  • [] setup env vars in GUI
  • [] git push heroku master/main