coders gyan(rest api) ---> book library(1.2)

api creation —>(user —>register and login)

postman—> elib(collection)—>user(folder)—>Register

Register

—> post —> localhost:5513/api/users/register

—>body—>raw—>json

{
"name":"",
"email":"",
"password":""
}

feature wise seperation of code

// src/user/userRouter.ts
import express from "express";
import { createUser, loginUser } from "./userController";

const userRouter = express.Router();
// routes
userRouter.post("/register", createUser);
userRouter.post("/login", loginUser);

export default userRouter;
// app.ts
import express, { NextFunction, Request, Response } from "express";
import globalErrorHandler from "./middlewares/globalErrorHandler";
import userRouter from "./user/userRouter";
import { config } from "./config/config";

const app = express();

app.use(express.json()); // help to parse data(sent from client/user) from req.body

// Routes
// Http methods: GET, POST, PUT, PATCH, DELETE
app.get("/", (req, res, next) => {
    res.json({ message: "Welcome to elib apis" });
});

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

// Global error handler
app.use(globalErrorHandler);

export default app;
// src/user/userTypes.ts
export interface User {
  _id: string;
  name: string;
  email: string;
  password: string;
}
// src/user/userModel.ts
import mongoose from "mongoose";
import { User } from "./userTypes";

const userSchema = new mongoose.Schema<User>(
  {
    name: {
      type: String,
      required: true,
    },
    email: {
      type: String,
      unique: true,
      required: true,
    },
    password: {
      type: String,
      required: true,
    },
  },
  { timestamps: true }
);

// default collection in plural and converted into smallcase-->(User -> users)
export default mongoose.model<User>("User", userSchema);
npm i bcrypt  # to hash password before storing to db
npm i -D @types/bcrypt

npm i jsonwebtoken  # to create token, only token user will be able to access data and certain feature
npm i -D @types/jsonwebtoken
// src/user/userController.ts
import { NextFunction, Request, Response } from "express";
import createHttpError from "http-errors";
import bcrypt from "bcrypt";
import userModel from "./userModel";
import { sign } from "jsonwebtoken";
import { config } from "../config/config";
import { User } from "./userTypes";

const createUser = async (req: Request, res: Response, next: NextFunction) => {
  const { name, email, password } = req.body;

  // Validation
  if (!name || !email || !password) {
    const error = createHttpError(400, "All fields are required");
    return next(error);
  }

  // Database call.
  try {
    const user = await userModel.findOne({ email });
    if (user) {
      const error = createHttpError(
        400,
        "User already exists with this email."
      );
      return next(error);
    }
  } catch (err) {
    return next(createHttpError(500, "Error while getting user"));
  }

  /// password -> hash
  // password + salt (salt No) --> random string
  const hashedPassword = await bcrypt.hash(password, 10);

  let newUser: User;
  try {
    newUser = await userModel.create({
      name,
      email,
      password: hashedPassword,
    });
  } catch (err) {
    return next(createHttpError(500, "Error while creating user."));
  }

  try {
    // Token generation JWT
    const token = sign({ sub: newUser._id }, config.jwtSecret as string, {
      expiresIn: "7d",
      algorithm: "HS256",
    });
    // Response
    res.status(201).json({ accessToken: token });
  } catch (err) {
    return next(createHttpError(500, "Error while signing the jwt token"));
  }
};

const loginUser = async (req: Request, res: Response, next: NextFunction) => {
  const { email, password } = req.body;

  if (!email || !password) {
    return next(createHttpError(400, "All fields are required"));
  }

  // todo: wrap in try catch.
  const user = await userModel.findOne({ email });
  if (!user) {
    return next(createHttpError(404, "User not found."));
  }

  const isMatch = await bcrypt.compare(password, user.password);

  if (!isMatch) {
    return next(createHttpError(400, "Username or password incorrect!"));
  }

  // todo: handle errors
  // Create accesstoken
  const token = sign({ sub: user._id }, config.jwtSecret as string, {
    expiresIn: "7d",
    algorithm: "HS256",
  });

  res.json({ accessToken: token });
};

export { createUser, loginUser };

Login

—> post —> localhost:5513/api/users/login

—>body—>raw—>json

{
"email":"",
"password":""
}