Crud-app #1

Open
jaanvi wants to merge 2 commits from dev into main
12 changed files with 323 additions and 50 deletions

27
app.js
View file

@ -2,30 +2,23 @@ require("dotenv").config();
const express = require("express");
const connectDB= require("./config/db");
const userRoutes= require("./routes/userRoutes");
const authRoutes = require("./routes/authRoutes");
const logger = require('./middleware/logger')
const app= express();
const PORT = process.env.PORT || 5000;
//DB connection:Done
connectDB();
//use in built-middleware to parse the data form body
//parse the json data
app.use(express.json());
//parse the url-encoded data
app.use(express.urlencoded({ extended: false }));
app.use(logger);
//Routes
app.use("/api/users",userRoutes);
app.use("/api/user", authRoutes);
app.listen(PORT,()=>{
console.log(`Server is running on port ${PORT}`);
})
// const logger = require("./middleware/logger");
// const userRoutes = require("./routes/userRoutes");
// const app = express();
// const PORT = process.env.PORT || 5000;
// connectDB();
// app.use(express.json());
// app.use(logger); // custom middleware
// app.use("/api/users", userRoutes);
// app.listen(PORT, () => {
// console.log(`Server is running on port ${PORT}`);
// });

View file

@ -1,4 +1,5 @@
const mongoose = require("mongoose");
const connectDB = async()=>{
try{
await mongoose.connect(process.env.MONGO_URI);
@ -9,4 +10,7 @@ const connectDB = async()=>{
}
}
module.exports = connectDB;
module.exports = connectDB;

View file

@ -0,0 +1,58 @@
const User = require("../models/User");
const jwt = require("jsonwebtoken");
const generateToken = (id) => {
return jwt.sign({ id }, process.env.JWT_SECRET, { expiresIn: "1h" });
};
//Register
const registerUser = async (req, res) => {
const { username, email, password } = req.body;
try {
const userExists = await User.findOne({ email });
if (userExists)
return res.status(400).json({ message: "User already exists" });
const user = await User.create({ username, email, password });
res.status(201).json({
_id: user._id,
username: user.username,
email: user.email,
token: generateToken(user._id),
});
} catch (error) {
console.error("Error in registerUser:", error.message);
res.status(500).json({ message: "Server error" });
}
};
//Login
const loginUser = async (req, res) => {
const { email, password } = req.body;
try {
const user = await User.findOne({ email });
if (!user) return res.status(400).json({ message: "Invalid credentials" });
const isMatch = await user.matchPassword(password);
if (!isMatch)
return res.status(400).json({ message: "Invalid credentials" });
res.status(200).json({
_id: user._id,
username: user.username,
email: user.email,
token: generateToken(user._id),
message: "success",
});
} catch (error) {
res.status(500).json({ message: "Server error" });
}
};
const getProfile = async (req, res) => {
res.json(req.user);
};
module.exports = { registerUser, loginUser, getProfile };

View file

@ -6,17 +6,18 @@ const createUser = async (req, res) => {
const user = await User.create(req.body);
res.status(201).json(user);
} catch (err) {
res.status(400).json({ error: err.message });
res.status(500).json({ error: err.message });
}
};
//GET
//GET
//if i use findOne then it fetching the first match data
const getUsers = async (req, res) => {
try {
const users = await User.find();
res.status(200).json(users);
} catch (err) {
res.status(400).json({ error: err.message });
res.status(500).json({ error: err.message });
}
};
@ -29,18 +30,19 @@ const getUserById = async (req,res)=>{
}
res.status(200).json(user);
} catch (err) {
res.status(400).json({ error: err.message });
res.status(500).json({ error: err.message });
}
};
//UPDATE
//UPDATE
const updateUser = async(req,res)=>{
try {
const user = await User.findByIdAndUpdate(req.params.id,req.body,{
new:true,
new:true,//return updated document
});
if(!user) return res.status(404).json({message: "User Not Found."})
res.status(200).json(user);
} catch (err) {
res.status(400).json({ error: err.message });
res.status(500).json({ error: err.message });
}
};
//DELETE
@ -50,8 +52,9 @@ const deleteUser= async(req,res)=>{
if(!user){
return res.status(404).json({message: "User not found"});
}
} catch (error) {
res.status(400).json({ error: err.message });
res.status(200).json({message:"success"})
} catch (err) {
res.status(500).json({ error: err.message });
}

View file

@ -0,0 +1,24 @@
const jwt = require("jsonwebtoken");
const User = require("../models/User");
const authToken = async (req, res, next) => {
let token;
if (
req.headers.authorization &&
req.headers.authorization.startsWith("Bearer")
) {
try {
token = req.headers.authorization.split(" ")[1]; // Correct split by space
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = await User.findById(decoded.id).select("-password");
next();
} catch (error) {
console.error(error);
res.status(401).json({ message: "Not authorized, token failed" });
}
} else {
res.status(401).json({ message: "Not authorized, no token" });
}
};
module.exports = authToken;

6
middleware/logger.js Normal file
View file

@ -0,0 +1,6 @@
// logger.js
function logger(req, res, next) {
console.log(`${req.method} ${req.url} at ${new Date().toISOString()}`);
next();
}
module.exports = logger;

View file

@ -1,19 +1,41 @@
const mongoose = require("mongoose");
const bcrypt = require("bcrypt");
const userSchema = new mongoose.Schema({
first_name:{
type:String,
required:true
},
last_name:{
type:String,
},
email:{
type:String,
required:true,
unique:true
},
age:{
type:Number
}
})
module.exports = mongoose.model("User",userSchema);
first_name: {
type: String,
required: false,
},
last_name: {
type: String,
},
email: {
type: String,
required: true,
unique: true,
},
age: {
type: Number,
},
username: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
});
userSchema.pre("save", async function (next) {
if (!this.isModified("password")) return next();
const salt = await bcrypt.genSalt(10);
this.password = await bcrypt.hash(this.password, salt);
next();
});
userSchema.methods.matchPassword = async function (enteredPassword) {
return await bcrypt.compare(enteredPassword, this.password);
};
module.exports = mongoose.model("User", userSchema);

4
nodemon.json Normal file
View file

@ -0,0 +1,4 @@
{
"watch": ["."],
"legacyWatch": true
}

140
package-lock.json generated
View file

@ -9,8 +9,10 @@
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"bcrypt": "^6.0.0",
"dotenv": "^16.5.0",
"express": "^5.1.0",
"jsonwebtoken": "^9.0.2",
"mongodb": "^6.16.0",
"mongoose": "^8.15.1",
"nodemon": "^3.1.10"
@ -72,6 +74,20 @@
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"license": "MIT"
},
"node_modules/bcrypt": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-6.0.0.tgz",
"integrity": "sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"node-addon-api": "^8.3.0",
"node-gyp-build": "^4.8.4"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/binary-extensions": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
@ -135,6 +151,12 @@
"node": ">=16.20.1"
}
},
"node_modules/buffer-equal-constant-time": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
"license": "BSD-3-Clause"
},
"node_modules/bytes": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@ -272,7 +294,6 @@
"version": "16.5.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz",
"integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=12"
},
@ -294,6 +315,15 @@
"node": ">= 0.4"
}
},
"node_modules/ecdsa-sig-formatter": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
"license": "Apache-2.0",
"dependencies": {
"safe-buffer": "^5.0.1"
}
},
"node_modules/ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@ -358,7 +388,6 @@
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz",
"integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==",
"license": "MIT",
"dependencies": {
"accepts": "^2.0.0",
"body-parser": "^2.2.0",
@ -657,6 +686,49 @@
"integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
"license": "MIT"
},
"node_modules/jsonwebtoken": {
"version": "9.0.2",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
"integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
"license": "MIT",
"dependencies": {
"jws": "^3.2.2",
"lodash.includes": "^4.3.0",
"lodash.isboolean": "^3.0.3",
"lodash.isinteger": "^4.0.4",
"lodash.isnumber": "^3.0.3",
"lodash.isplainobject": "^4.0.6",
"lodash.isstring": "^4.0.1",
"lodash.once": "^4.0.0",
"ms": "^2.1.1",
"semver": "^7.5.4"
},
"engines": {
"node": ">=12",
"npm": ">=6"
}
},
"node_modules/jwa": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz",
"integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==",
"license": "MIT",
"dependencies": {
"buffer-equal-constant-time": "^1.0.1",
"ecdsa-sig-formatter": "1.0.11",
"safe-buffer": "^5.0.1"
}
},
"node_modules/jws": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
"license": "MIT",
"dependencies": {
"jwa": "^1.4.1",
"safe-buffer": "^5.0.1"
}
},
"node_modules/kareem": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz",
@ -666,6 +738,48 @@
"node": ">=12.0.0"
}
},
"node_modules/lodash.includes": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
"integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
"license": "MIT"
},
"node_modules/lodash.isboolean": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
"integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
"license": "MIT"
},
"node_modules/lodash.isinteger": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
"integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
"license": "MIT"
},
"node_modules/lodash.isnumber": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
"integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
"license": "MIT"
},
"node_modules/lodash.isplainobject": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
"license": "MIT"
},
"node_modules/lodash.isstring": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
"integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
"license": "MIT"
},
"node_modules/lodash.once": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
"integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
"license": "MIT"
},
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
@ -739,7 +853,6 @@
"version": "6.16.0",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.16.0.tgz",
"integrity": "sha512-D1PNcdT0y4Grhou5Zi/qgipZOYeWrhLEpk33n3nm6LGtz61jvO88WlrWCK/bigMjpnOdAUKKQwsGIl0NtWMyYw==",
"license": "Apache-2.0",
"dependencies": {
"@mongodb-js/saslprep": "^1.1.9",
"bson": "^6.10.3",
@ -795,7 +908,6 @@
"version": "8.15.1",
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.15.1.tgz",
"integrity": "sha512-RhQ4DzmBi5BNGcS0w4u1vdMRIKcteXTCNzDt1j7XRcdWYBz1MjMjulBhPaeC5jBCHOD1yinuOFTTSOWLLGexWw==",
"license": "MIT",
"dependencies": {
"bson": "^6.10.3",
"kareem": "2.6.3",
@ -849,6 +961,26 @@
"node": ">= 0.6"
}
},
"node_modules/node-addon-api": {
"version": "8.3.1",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.3.1.tgz",
"integrity": "sha512-lytcDEdxKjGJPTLEfW4mYMigRezMlyJY8W4wxJK8zE533Jlb8L8dRuObJFWg2P+AuOIxoCgKF+2Oq4d4Zd0OUA==",
"license": "MIT",
"engines": {
"node": "^18 || ^20 || >= 21"
}
},
"node_modules/node-gyp-build": {
"version": "4.8.4",
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz",
"integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==",
"license": "MIT",
"bin": {
"node-gyp-build": "bin.js",
"node-gyp-build-optional": "optional.js",
"node-gyp-build-test": "build-test.js"
}
},
"node_modules/nodemon": {
"version": "3.1.10",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz",

View file

@ -3,7 +3,7 @@
"version": "1.0.0",
"main": "app.js",
"scripts": {
"start":"nodemon app.js",
"start": "nodemon app.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
@ -11,10 +11,14 @@
"license": "ISC",
"description": "",
"dependencies": {
"bcrypt": "^6.0.0",
"dotenv": "^16.5.0",
"express": "^5.1.0",
"jsonwebtoken": "^9.0.2",
"mongodb": "^6.16.0",
"mongoose": "^8.15.1",
"nodemon": "^3.1.10"
}
}

21
routes/authRoutes.js Normal file
View file

@ -0,0 +1,21 @@
const express = require("express");
const {
registerUser,
loginUser,
getProfile,
} = require("../controllers/authController");
const authToken = require("../middleware/authMiddleware");
const router = express.Router();
// Register user
router.post("/register",registerUser );
// Login user
router.post("/login", loginUser);
//protectRoute
router.get("/profile", authToken, getProfile);
module.exports = router;

View file

@ -6,4 +6,6 @@ router.post("/", createUser);
router.get('/',getUsers);
router.get('/:id',getUserById);
router.put('/:id',updateUser);
router.delete(':/id',deleteUser)
router.delete('/:id',deleteUser)
module.exports = router;