Skip to content

My code from following the Udemy course "Node.js, Express, MongoDB & More: The Complete Bootcamp", with adjustments and workarounds to keep the project running in 2025.

Notifications You must be signed in to change notification settings

ElenaChes/node-js-practice-1

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

25 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Node.js practice #1 - Webapp

This repo contains my code from following the Udemy course Node.js, Express, MongoDB & More: The Complete Bootcamp.
Since the course is now outdated (several tools and APIs have changed), I made adjustments and workarounds to keep the project running in 2025.
You can see the list of changes and extra features I implemented below — this may be useful for fellow students or anyone revisiting the course.

Note

For the original unmodified source code, see the instructor’s repo: complete-node-bootcamp.

Content


Part 4: Natours - Changes & Adjustments

Mongoose (Unit 83)

If you install the old version used in the course ([email protected]), you’ll see a deprecation warning when connecting to the DB:

(node:15396) [DEP0170] DeprecationWarning: The URL <DATABASE URL> is invalid. Future versions of Node.js will throw an error.

You have two options:

  • Upgrade to a newer version of Mongoose.
  • Ignore the warning - as of 2025, everything still works despite of it.

I decided to stick with the course’s older version just in case there were breaking changes, but in my experience with newer Mongoose versions (^7) everything (schemas, methods, etc.) still works the same. The only noticeable difference is in the connection options:

//before (v5)
mongoose
  .connect(DB, {
    useNewUrlParser: true,
    useCreateIndex: true,
    useFindAndModify: false,
    useUnifiedTopology: true, //hide extra warnings
  })
  .then(() => console.log("DB connection successful!"));

//after (v7)
mongoose
  .connect(DB)
  .then(() => console.log("DB connection successful!"))
  .catch((err) => console.error(err));

In v7 options like useNewUrlParser, useCreateIndex and useFindAndModify no longer exist (they're used by default). useUnifiedTopology was only needed to suppress old warnings.

Debugging with ndb (Unit 111)

While ndb isn't technically outdated, I found VS Code's built-in debugger more user-friendly and sufficient for this course.
I created a .vscode/launch.json file following the steps described here: ndb vs Visual Studio debugger, after which VS Code's debugger started working.

Note

Unlike ndb, VS Code doesn't have a single-step button. Instead there are:

  • Step Over - to move forward line by line without entering functions.
  • Step Into - to dive into a function call.
  • Step Out - to skip the current function and return to the caller.

Mongoose Validation Errors (Unit 121)

The structure of Mongoose errors has changed since the course was recorded, which breaks the handleDuplicateFieldsDB function.
The old err.errmsg field no longer exists, instead we can get the duplicate keys from err.keyValue:

//before
const value = err.errmsg.match(/(["'])(\\?.)*?\1/)[0];

//after
const value = Object.values(err.keyValue)
  .map((val) => `"${val}"`)
  .join(", ");

The course doesn’t cover this error in depth (likely because compound indexes aren’t used until later) - in this project, it can be triggered when creating a tour with a name that already exists, signing up a user with a taken email, or when a user tries to review a tour twice.

To make the error messages more informative for compound indexes ({ tour: 1, user: 1 }, { unique: true }) I customized the error further:

const collectionMatch = err.message.match(/collection:\s([^.]+)\.(\w+)/);
const collectionName = collectionMatch ? collectionMatch[2] : null;
let message = "";
if (err.keyPattern.tour && err.keyPattern.user) {
  if (collectionName === "bookings") {
    message = `User ${err.keyValue.user} has already booked tour ${err.keyValue.tour}.`;
  } else if (collectionName === "reviews") {
    message = `User ${err.keyValue.user} has already left a review on tour ${err.keyValue.tour}.`;
  } else {
    //fallback (unknown collection)
    message = `Duplicate entry for user ${err.keyValue.user} and tour ${err.keyValue.tour} in collection "${collectionName}".`;
  }
} else {
  const value = Object.values(err.keyValue)
    .map((val) => `"${val}"`)
    .join(", ");
  message = `Duplicate field value: ${value}. Please use another value!`;
}

Importing users from dev-data (Unit 166)

The default test1234 password wouldn't work for me once I used the import script - it seems that the user passwords in users.json are already encrypted so letting the model's pre-save middleware encrypt them gets them double encrypted.
I followed the following steps to fix the issue: How to correct POST 401 (Unathorized) Error after Entering Password test1234

Mapbox (Unit 186&187)

As of 2025 Mapbox asks for a credit card to register an account.
I used Leaflet instead using the following setup: Leaflet instead of mapbox You can see my setup in leaflet.js and tour.pug.

Sendgrid (Unit 209)

Like others I found Sendgrid's requirements way too high for a practice project and used Brevo instead.
Instructions to set it up: SOLUTION!! SendGrid not working? Use Brevo(ex SendinBlue) in 3 simple steps. My Brevo secrets are taken from the SMTP tab and set up the following way:

BREVO_USERNAME=<Login>
BREVO_PASSWORD=<SMTP key value>
BREVO_EMAIL_HOST=<SMTP Server>
BREVO_EMAIL_PORT=<Port>

EMAIL_FROM=<email>

I set a real email as EMAIL_FROM, haven't tested with a fake one.

Stripe session (Unit 211&212)

Even when using [email protected] the API doesn't work the same as the course anymore.
Stripe expects a different data structure: StripeInvalidRequestError - version: [email protected] SOLUTION.

The payments don't appear on Stripe right away like in the course, and rather wait until you perform a transaction - here's an explanation on the process and the fake cards Stripe supplies for testing: Payments not in Dashboard.
Additionally, as of 2025 the test payments don't appear in Stripe on a page called Payments but rather Transactions.

Lastly, www.natours.dev is no longer online so it's impossible to use it for images. I solved it by using the course's GitHub repo for the images:

//before
images: [`https://www.natours.dev/img/tours/${tour.imageCover}`];

//after
images: [
  `https://github.com/jonasschmedtmann/complete-node-bootcamp/blob/master/4-natours/starter/public/img/tours/${tour.imageCover}?raw=true`,
];

Of course this solution can't work for new custom tours, but the original can't work for new tours either (at least until it's changed to the url of the live website).

Heroku (Unit 223)

Heroku discontinued its free hosting tier in November 2022.
I originally experimented with Heroku before that change, but later migrated my deployments to Fly.io (which, as far as I know, no longer offers a truly free tier either as only legacy users have access to a hobby plan).

Since this course focused specifically on Heroku’s web UI rather than deployment workflows in general, I chose to skip this step and not search for alternative deployment options for the course.
As a result, this project was not tested as a live website. That said, I do have other apps deployed - if you're interested, check out my Fly.io deployment crash course & Docker examples.

Stripe Webhooks (Unit 227)

Just like the previous time we used Stripe, the website changed quite a bit since the course was recorded so now the process is:

  1. Go to Developers (bottom of the screen) -> Webhooks -> click +Add destination.

Note

I initially got a "Limited access to Workbench" message when opening the Webhooks tab. I’m not exactly sure why, but opening Stripe from the welcome email fixed it and refreshed the UI - almost like I was originally partially logged in.

  1. The fields in the form changed:

    • Endpoint URL -> Not shown in this step, but it appears later.
    • Version -> now called API version (presumably can select the latest).
    • Events to send -> Open checkout and select checkout.session.completed.
  2. Click Continue, then select Webhook endpoint and Continue again.

  3. Now you'll see the webhook specific fields:

    • Destination name: whatever you'd like.
    • Endpoint URL: this is the same field as in the course -> https://<deployed app>/webhook-checkout.
    • Description: whatever you'd like.

Note that I skipped deploying the app so I haven't tested the webhook, but there don't appear to be any settings in this flow that would prevent the webhook from working.

Part 4: Natours - Extras & Bonus

Bonus challenges (Unit 217)

From the list of suggested challenges in this unit, I implemented the following:

  • Users can only review tours they have booked:
    • Added middleware hasBookedTour in reviewController.js
    • Updated reviewRoutes.js
  • Nested booking routes (GET & POST /tours/:id/bookings):
    • Added nested route intourRoutes.js
    • Updated bookingRoutes.js and bookingController.js
  • Hide bookings section if user already booked the tour & prevent duplicate bookings:
    • Updated bookingModel.js
    • Added check in viewsController.js
    • Updated tour.pug
  • "My Reviews" page (non-React):
    • Added getMyReviews in viewsController.js
    • Added route /my-reviews in viewRoutes.js
    • Added reviews.pug with custom cards

About

My code from following the Udemy course "Node.js, Express, MongoDB & More: The Complete Bootcamp", with adjustments and workarounds to keep the project running in 2025.

Topics

Resources

Stars

Watchers

Forks