About the Portfolio Project: E-Commerce Website category

The E-Commerce Website I Project

Welcome to the subcategory for the E-Commerce Website Project. This portfolio project can be found in the following courses or paths:

  • Full Stack Engineer Path

How to Get Feedback on your Project

Congratulations on finishing your portfolio project! Now you’ll want to follow these steps to get feedback on it.

  1. Post a link to your git repository :slight_smile:
  2. Give us a few sentences about your experience. Was this fun? Difficult? How long did it take?
  3. Check back in—if someone has replied to your post, come see what they have to say.

How to Give Feedback on Another Learner’s Project

Reviewing someone else’s code isn’t just a nice thing to do; it’s also a great opportunity to sharpen your skills by viewing a different perspective.

  1. Refer to the article in your Career Path on How to Review Someone Else’s Code
  2. Click through topics in this subcategory to view other submissions of this project.
  3. Reply to a thread with feedback, encouragement, or letting them know if they did something in a way you hadn’t thought of before!

This was a good project and fairly challenging to put all the pieces together. Took 11 days but will probably adjust it a bit when developing the front-end. The bigger challenges were database schema design, structuring the Express app (since Express is fairly unopinionated), getting authentication/authorization to work good, and setting up Swagger doc where there are some different ways of doing it and document standards (swagger 2.0 vs openapi 3.0, yaml, json, in-line comments and so on)…

I ended up using passport-local, passport-jwt, bcrypt, and jsonwebtoken for auth where I store the JWT in a cookie after login that expires after 60min. Used swagger-ui-express for documentation but only documented the routes to be used for front-end customer access. Most of the Swagger “try it out” feature does currently not work due to the authentication requirements for the api but I will look at that more later. Also made some “admin” routes that I didn’t document at this point since I am not planning to make an admin dashboard initially.

Github repo
Deployed API docs

Hi everybody!

I really enjoyed this challenge, and I think I learned a lot, I would like you to share your opinions with me if you want.

Please take a look at my e-commerce app in github: Postres de la abuela
Note: if you want to see the live version take a look at the readme.md file and click the link in the setup section

1 Like

Quick update on project. Deployed front-end as well (link provided) and appreciate code review or any bug-reports/feedback:
https://treasurespace.netlify.app/

https://github.com/mikejoh12/e-commerce

Here is something I learned: First deployed API on Heroku and then front-end via Netlify. I am using cookies for JWT authentication so the auth-cookie would come from heroku but React site from Netlify. A lot of Browsers nowadays do not like cookies sent from another web-site (3rd party cookies) and blocks them by default (on Apple products for example). So I had a problem and needed a way to send cookies from/via Netlify. The fix was to set up a proxy throught Netlify (one line in the _redirects file) and this fixed the issue as the front-end could now fetch from the netlify site under the /api path. I could have also served the React site from the Express server… Just some things to consider for the project if you end up using cookies!

2 Likes

Wow this is a challenging project, but very rewarding as well. I was lucky to have Mike who has helped me a lot in this project. What I find the hardest were:

  • Understanding the authentication and authorization flow, and which method is more secure, and how to implement that method. I ended up using passport-local strategy for authenticating user when they first log in, then create a JWT and set it in a secure and httpOnly cookie, this cookie would be send by the client every time. To authenticate user for a protected route such as profile, I use passport-jwt to authenticate user based on the JWT in the cookie being sent with the request.

  • How to redirect user when they are trying to access protected route before logging in.

  • What is the best way to manage cart, how to make cart persist, and how to make database schema so that items in cart get to into database logically, so that you can find the associated orders for a particular account to display in the profile/user page.

  • Deploying to Heroku was difficult as well. As there were many things that could (and did) go wrong. Dont hardcode your PORT, use environment variable for port (process.env.PORT). For connection with database, use process.env.DATABASE_URL for production. Use relative path when trying to fetch data from server, don’t hard code it like fetch('localhost:3000/api...) . Need to set up your package.json accordingly. Need to set up your routes, see the server/index.js file in my repo for more info on this.

Deployed both front and back end to Heroku. Please let me know what you all think, and any bugs you caught.

Live: https://e-commerce-apple.herokuapp.com/
Github Repo: GitHub - edphan/e-commerce-appleclone: An e-commerce project React-Redux-Nodejs Express-PostgreSQL

1 Like

Oh My Word.

This project genuinely took me a full month to complete. Possibly I wrong-footed myself a little by trying to do this with TDD, which led me down different rabbit holes in terms of dealing with mocha, chai, superagent, knex, etc. It really felt like every tiny step forward in the project required me to learn a crazy amount - honestly, it’s pretty weird how much of the stuff in this project is not covered before this point of the course. But I’m very proud of finishing it.

My swagger documentation is here: Swagger UI
And my github repo is here (no readme as yet, that’ll be a tomorrow problem): GitHub - jrosk089/inharmony_api: A backend using Node, Express, Postgres and Knex

2 Likes

Hi All
I am running into this issue when deploying to heroku .
My front end works fine ,backend api calls comes back with 400 error bad request.
This is my link for github repo :

It has something to do with setupProxy.js file in src/ folder, but i have tried millions of things.
Couldnt figure out what’s wrong
If anybody can look in my code esp setupProxy.js file, will be really helpful.

Phew.I have resolved it.That was a long list of errors i had to resolve, but its finally working.
I just need to put test data in my application.
Things to do :

  1. Facebook + Google login
  2. account details

Here is the link of project

Do you have a link to the deployed project?

Refresh the page ,if it doesnt work on the first attempt, i dont know it happens to me,
Heroku gives me application error on first attempt, after that it starts working

Hi All,

I hope you are well!

I am trying to finish this project which has taken longer than what i have expected and i am still running into the issue when trying to use Passport.js with local-strategy to go to login endpoint.

In my index.js i have set up the login endpoint and Passport.js configuration as well but it seems i am missing very basic detail and it seems the server is running but Passport.Initialize() seems not working at all and having issue not getting user in request which i can access later on to authenticate with Passport.

I have added the code snippet for index.js here. Can anyone please look into this and please guide me. To start with Passport.js concept is very difficult to understand on first go and this is where i am missing something. Rest endpoints are working fine and getting data through Postman.

Only login endpoint is the issue when I make POST request on ‘http://localhost:5000/auth/login’ with request.body data

Please see below : index.js

const express = require(“express”);

const uuid = require(“uuid”).v4;

const app = express();

const cors = require(“cors”);

const session = require(“express-session”);

const FileStore = require(“session-file-store”)(session);

//const bodyParser = require(“body-parser”);

const userDB = require("./db/userqueries");

const passport = require(“passport”);

const LocalStrategy = require(“passport-local”).Strategy;

let port = process.env.PORT;

if (port == null || port == “”) {

port = 5000;

}

// Enable Cross Origin Resource Sharing to all origins by default

app.use(cors());

// Configure local strategy to be use for local login

passport.use(

new LocalStrategy(

{

  usernameField: "email",

},

async (email, password, done) => {

  try {

    console.log("inside passport");

    const user = await userDB.authenticateUser({

      email: email,

      password: password,

    });

    console.log("Local strategy returned true");

    console.log(user);

    if (!user) {

      console.log("Incorrect email or password.");

      return done(null, false, { message: "Incorrect email or password." });

    }

    return done(null, user, { message: "Logged in Successfully" });

  } catch (error) {

    console.log("Local strategy returned false");

    return done(error);

  }

}

)

);

// Transforms raw string of req.body into JSON

//app.use(bodyParser.json());

app.use(express.json());

// Creates a session

app.use(

session({

/*genid: (req) => {

  console.log("Inside session middleware genid function");

  console.log(`Request object sessionID from client: ${req.sessionID}`);

  return uuid(); // use UUIDs for session IDs

},*/

secret: process.env.SESSION_SECRET || "session_secret",

resave: false,

saveUninitialized: true,

//store: new FileStore({ logFn: function () {} }),

})

);

//app.use(bodyParser.urlencoded({ extended: false }));

app.use(express.urlencoded({ extended: false }));

// Initialize passport

app.use(passport.initialize());

app.use(passport.session());

// Set method to serialize data to store in cookie

passport.serializeUser((user, done) => {

console.log(“serializing”);

console.log(user);

done(null, user.id);

});

// Set method to deserialize data stored in cookie and attach to req.user

passport.deserializeUser((id, done) => {

console.log(“deserializing”);

done(null, id);

// const user = users[0].id === id ? users[0] : false;

// done(null, user);

});

app.get("/", (request, response) => {

response.json({ info: “Node.js, Express, and Postgres API” });

});

/* Login Endpoint*/

app.post("/auth/login", (req, res, next) => {

console.log(req.body);

console.log(“Inside POST /login callback”);

passport.authenticate(“local”, (err, user, info) => {

console.log("Inside passport.authenticate() callback");

console.log(

  `req.session.passport: ${JSON.stringify(req.session.passport)}`

);

console.log(`req.user: ${JSON.stringify(req.user)}`);

req.login(user, (err) => {

  console.log("Inside req.login() callback");

  console.log(

    `req.session.passport: ${JSON.stringify(req.session.passport)}`

  );

  console.log(`req.user: ${JSON.stringify(req.user)}`);

  return res.status(200).send("You were authenticated & logged in!\n");

});

})(req, res, next);

});

/* Check auth*/

app.get("/authrequired", (req, res) => {

console.log(“Inside GET /authrequired callback”);

console.log(User authenticated? ${req.user});

console.log(req.session);

console.log(User authenticated? ${req.session});

if (req.isAuthenticated()) {

res.send("you hit the authentication endpoint\n");

} else {

console.log("invalid");

res.send("invalid");

}

});

// User Router

const userRouter = require("./routes/user");

app.use("/users", userRouter);

// Cart Router

const cartRouter = require("./routes/cart");

app.use("/cart", cartRouter);

// Products Router

const productRouter = require("./routes/product");

app.use("/products", productRouter);

// Order Router

const orderRouter = require("./routes/order");

app.use("/orders", orderRouter);

/*const swaggerUi = require(“swagger-ui-express”);

//const yaml = require(‘js-yaml’);

//const fs = require(‘fs’);

//const path = require(‘path’);

// Loading via yml.safeLoad to avoid errors with special characters during processing

//const swaggerDocument = yaml.load(fs.readFileSync(path.resolve(__dirname, ‘./swagger.yml’), ‘utf8’));

const swaggerDocument = require("./swagger.json");

// Serves Swagger API documentation to /docs url

app.use("/docs", swaggerUi.serve, swaggerUi.setup(swaggerDocument));*/

app.listen(port, () => {

console.log(Listening on the port ${port}.);

});

It gives me below output on console:

Listening on the port 5000.
{ email: ‘r@e1.com’, pwd: ‘re1’ }
Inside POST /login callback
Inside passport.authenticate() callback
req.session.passport: undefined
req.user: undefined
serializing
false
Inside req.login() callback
req.session.passport: undefined
req.user: null

The problem is it is not calling Passport.initialize() at all and this is where all issues are starting.

I would be much appreciated if anyone can help :slight_smile:

Thanks in advance for your time and help for looking into this matter.

Hope you have a great day :slight_smile:

Naiya

Do you have a link to a public github repo with the code? That would be easiest to look at. If not, you can use the </> code-formatting feature of this editor and paste in several code-snippets representing the relevant files.

Hi Mike,

Thank you for your coming back.

You can find the code on my github @ GitHub - naiyagpatel/E-CommerceApp-RESTAPI-Naiya: A REST API with Node, Express and POSTGRES

Any suggestions would be much appreciated.

Looking forward to hear from you.

Thanks again and hope you have a good day :slight_smile:

Naiya

Hey, one thing that first comes to my attention is in your local strategy you shouldn’t change the username to email inside the async function. I hope that helps


new LocalStrategy(

{

  usernameField: "email",

},
//this one here should still be username
//by assigning usernameField: "email" you tell passport to look for email key from your request/login details
async (username, password, done) => {

  try {

    console.log("inside passport");

    const user = await userDB.authenticateUser({

      email: email,

      password: password,

    });

    console.log("Local strategy returned true");

    console.log(user);

    if (!user) {

      console.log("Incorrect email or password.");

      return done(null, false, { message: "Incorrect email or password." });

    }

    return done(null, user, { message: "Logged in Successfully" });

  } catch (error) {

    console.log("Local strategy returned false");

    return done(error);

  }

})

Hi, my user database has email as PK which should be checked against when user tries to login and not username that’s why i have changed to email.

If this is the case then i should be using email rather than username, right?

Hope this make sense…

Please let me know :slight_smile:

Naiya

Try it like that, it sorted the same problem for me when I first used passport.

new LocalStrategy(

{
  usernameField: "email",
  passwordField: "password"
},

async (username, password, done) => {............})

I looked quickly and here are a couple of comments and although they will not directly solve your problem hopefully they are of some help.

As a general rule, don’t commit the .env file to git since it usually contains passwords/secrets. Get in the habit of including .env on your .gitignore. Before you put the site live, at least make sure that the actual passwords used for deployment are not visible there.

Look at moving Express code out from index.js into an organized system. It is always harder to troubleshoot with one long file and there are some good guides online how to do it. I like a /config directory with a passport.js file for passport strategies and then require this file.

Go for a consistent way of handling async code - it will make it a lot easier to debug. You have a mix of async/await and callback-technique used. In some cases (createUser for example) there is async with callback and no await. Take a look at the official pg docs if you like to use async/await as they have a some good techniques using express-promise-router (avoiding all the try blocks):
https://node-postgres.com/guides/async-express

Finally, I would start with just getting the Passport-Local strategy to work before introducing express-session. And also check out bcrypt (which is pretty easy to learn) to store a hash in the db so that the actual password is not stored in the db.

Took a second look and got it working - check screenshot. I changed the code in app.post(‘login’, function) to use async/await/try - syntax. Also doublecheck that your postgres credentials are correct in .env. Function with changes:

/*  Login Endpoint*/
app.post("/login", async (req, res, next) => {
  console.log(req.body);
  console.log("Inside POST /login callback");
  passport.authenticate("local", async (err, user, info) => {
    console.log('Err:', err)
    console.log('User:', user)
    console.log('Info:', info)
    try {
    if (err || !user) {
      const error = new Error('An error occurred.');
      console.log(error.message)
      return next(error);
    }
    console.log("Inside passport.authenticate() callback");
    console.log(
      `req.session.passport: ${JSON.stringify(req.session.passport)}`
    );
    console.log(`req.user: ${JSON.stringify(req.user)}`);
    req.login(user, (err) => {
      console.log("Inside req.login() callback");
      console.log(
        `req.session.passport: ${JSON.stringify(req.session.passport)}`
      );
      console.log(`req.user: ${JSON.stringify(req.user)}`);
      return res.status(200).send("You were authenticated & logged in!\n");
    });
  } catch (e) {
    return next(e)
  }
  })(req, res, next);
});