NextJs What we are learning?
Nextjs project file structure before that let create the project : create-next-app@latest . Eraser.io
Defining Data Model, how forgot password is perform using forgot token.
Database connection
Helper function: Eg Mailer
Defining API in nextjs
File Structure: It is important to understand the folder structure of nextjs.
Top level folders: src, src/app, src/dbConfig, src/helpers, src/models, and src/.env.
Client code is located in app/pageName/page.tsx.
Backend code is in app/api, with subfolders for different functionalities (e.g., app/api/users for authentication, with login and signup subfolders). Each subfolder contains a app/api/users/login/route.ts file for routing.
Starting a Project first by defining environment variable:
Environment Variables (.env): Define variables like MONGO_URL, TOKEN_SECRET, and DOMAIN.
MONGO_URL=abc
TOKEN_SECRET=someSecret
DOMAIN=http://localhost:3000
Data Modeling (src/models/userModel.js):
npm i mongoose
Step 1: First step for project creation Define Data Modeling
Let first create User model, Define your data models using Mongoose. For example, a User model might include fields like username, email, password, isVerified, isAdmin, forgotPasswordToken, forgotPasswordTokenExpiry, verifyToken, and verifyTokenExpiry. Here's a simplified version of the User model:
how forgot token and expiretoken works?
In the given example, the user schema includes two fields related to the password reset functionality: `forgotPasswordToken` and `forgotPasswordTokenExpiry`. Here's a brief explanation of how they work:
1. When a user requests to reset their password, a new token is generated and stored in the `forgotPasswordToken` field for that user.
2. The token has an expiration time, which is stored in the `forgotPasswordTokenExpiry` field. This is typically set to a short time period, such as 1 hour, to ensure the token can only be used for a limited time.
3. The token is sent to the user's email address as a link to reset their password. The link includes the token as a query parameter.
4. When the user clicks the link, the application checks the token against the one stored in the `forgotPasswordToken` field for that user. If the token matches and has not expired (i.e., the current time is less than the `forgotPasswordTokenExpiry` time), the user is allowed to reset their password.
5. If the token is invalid or has expired, the user is shown an error message and prompted to request a new password reset token.
6. Once the user successfully resets their password, the `forgotPasswordToken` and `forgotPasswordTokenExpiry` fields are cleared or updated to prevent the old token from being used again.
In summary, the `forgotPasswordToken` and `forgotPasswordTokenExpiry` fields work together to provide a secure and time-limited way for users to reset their passwords.
In MongoDB and Mongoose, a schema is a blueprint for how your data should be structured in your database. It defines the shape of the documents within a collection, including the fields and their data types, default values, validation rules, and indexes.
Step 2: Data Modeling in Next.js:
Next.js uses edge computing, which means the schema doesn't know if it's connecting to MongoDB for the first time or not. To handle this, when exporting a model, you should check if the model already exists and return a reference to it. If it doesn't exist, create a new model. Here's how you can do it:
Step 3 Database Connection:
Create a dbConfig folder inside src and add a dbConfig.js file. Since the database could be located on a different server, there's no guarantee of a stable connection. Therefore, it's important to handle potential errors using try-catch blocks and async functions. Here's a simplified version of the database connection:
import mongoose from "mongoose";
export async function connect() { //Think database is always in other contenient
try {
mongoose.connect(process.env.MONGO_URL!);
const connection = mongoose.connection;
//Need of connnection because error can occurs after the connection
connection.on("connected", () => { console.log("MongoDB connected"); });
// where connected is event
connection.on("error", (err) => { // Callback func
console.log("MongoDB connection error. Please make sure DB is up and running ", err);
process.exit(); // No need to contiue
});
} catch (error) {
console.log("Something went wrong in connecting to DB");
console.error(error);
}
}
This code connects to the MongoDB database using the URL provided in the environment variables. It logs a message when the connection is successful and handles any errors that occur during the connection process. If an error occurs, it logs the error and exits the process.
Helper function:
All the helper function are put into the src/helpers/mailer.ts file. Creating a Helper Function for Sending Emails in Next.js:
Create a mailer.ts file inside a new helpers folder (src/helpers/mailer.ts).
Install nodemailer and bcryptjs using npm.
Import required modules: User, nodemailer, and bcryptjs.
Install nodemailer and bcryptjs using npm.
Import required modules: User, nodemailer, and bcryptjs.
import User from "@/models/userModel"; import nodemailer from "nodemailer";
import bcryptjs from "bcryptjs";
export const sendEmail = async ({ email, emailType, userId }: any) => {
try {
const hashToken = await bcryptjs.hash(userId.toString(), 10);
if (emailType === "VERIFY") {
await User.findByIdAndUpdate(userId, {
verifyToken: hashToken,
verifyTokenExpiry: Date.now() + 3600000,
});
} else if (emailType === "RESET") {
await User.findByIdAndUpdate(userId, {
forgotPasswordToken: hashToken,
forgotPasswordTokenExpiry: Date.now() + 3600000,
});
}
var transport = nodemailer.createTransport({
host: "sandbox.smtp.mailtrap.io",
port: 2525,
auth: { user: "10c305d04c1ceb", pass: "0b45ad377039e4" },
});
const mailOptions = {
from: "contact@tibetkart.com",
to: email,
subject: emailType === "VERIFY" ? "Verify your email" : "Reset your password",
html: `<p>Click <a href="${process.env.DOMAIN}/verifyemail?token=${hashToken}">here</a> to
${
emailType === "VERIFY" ? "Verify your email" : "Reset your password"
} or copy and paste the link below in your browser.
<br>
${process.env.DOMAIN}/verifyemail?token=${hashToken}
</p>`,
};
const mailResponse = await transport.sendMail(mailOptions);
return mailResponse;
} catch (error: any) {
throw new Error(error.message);
}
};
Defining Nextjs API: