Node.js Package Reference Guide
Core Dependencies
Web Framework & Server
-
express (^4.18.2)
- Web application framework
- Handles routing, middleware, and HTTP requests/responses
- Core foundation for building APIs and web applications
Database
-
mongoose (^7.0.0)
- MongoDB object modeling tool
- Provides schema-based solution to model application data
- Handles database operations and relationships
Security Packages
-
jsonwebtoken (^9.0.0)
- Creates and verifies JSON Web Tokens (JWT)
- Used for user authentication and secure information exchange
-
bcryptjs (^2.4.3)
- Hashes and compares passwords securely
- Protects user passwords in the database
-
helmet (^6.0.1)
- Adds security headers to HTTP responses
- Protects against common web vulnerabilities
- Sets various HTTP headers for security
-
cors (^2.8.5)
- Enables Cross-Origin Resource Sharing
- Controls which domains can access your API
- Essential for web applications with separate frontend/backend
Validation & Configuration
-
joi (^17.9.0)
- Data validation library
- Validates request bodies, query parameters, and other inputs
- Ensures data integrity and format
-
dotenv (^16.0.3)
- Loads environment variables from .env file
- Manages configuration settings
- Keeps sensitive data secure
Development Dependencies
Development Tools
-
nodemon (^2.0.22)
- Monitors file changes during development
- Automatically restarts the server
- Improves development workflow
Usage Example
// Express server setup
const express = require('express');
const app = express();
// Security middleware
const helmet = require('helmet');
const cors = require('cors');
app.use(helmet());
app.use(cors());
// Environment variables
require('dotenv').config();
// Database connection
const mongoose = require('mongoose');
mongoose.connect(process.env.MONGODB_URI);
// Validation example
const Joi = require('joi');
const schema = Joi.object({
email: Joi.string().email().required()
});
// Password hashing
const bcrypt = require('bcryptjs');
const hashedPassword = await bcrypt.hash('password', 10);
// JWT authentication
const jwt = require('jsonwebtoken');
const token = jwt.sign({userId: 123}, process.env.JWT_SECRET);
Complete Node.js and Mongoose Project Structure Guide
Project Structure
project-root/
├── src/
│ ├── config/
│ │ ├── database.js
│ │ └── config.js
│ ├── models/
│ │ ├── user.model.js
│ │ └── product.model.js
│ ├── controllers/
│ │ ├── user.controller.js
│ │ └── product.controller.js
│ ├── routes/
│ │ ├── user.routes.js
│ │ └── product.routes.js
│ ├── middleware/
│ │ ├── auth.middleware.js
│ │ └── error.middleware.js
│ ├── utils/
│ │ ├── logger.js
│ │ └── validators.js
│ └── app.js
├── .env
├── .gitignore
└── package.json
1. Initial Setup
package.json
{
"name": "node-mongoose-project",
"version": "1.0.0",
"main": "src/app.js",
"scripts": {
"start": "node src/app.js",
"dev": "nodemon src/app.js"
},
"dependencies": {
"express": "^4.18.2",
"mongoose": "^7.0.0",
"dotenv": "^16.0.3",
"joi": "^17.9.0",
"jsonwebtoken": "^9.0.0",
"bcryptjs": "^2.4.3",
"cors": "^2.8.5",
"helmet": "^6.0.1"
},
"devDependencies": {
"nodemon": "^2.0.22"
}
}
.env
PORT=3000
MONGODB_URI=mongodb://localhost:27017/your-database
JWT_SECRET=your-secret-key
NODE_ENV=development
.gitignore
node_modules/
.env
logs/
*.log
2. Configuration Setup
src/config/config.js
require('dotenv').config();
module.exports = {
port: process.env.PORT || 3000,
mongoUri: process.env.MONGODB_URI,
jwtSecret: process.env.JWT_SECRET,
nodeEnv: process.env.NODE_ENV || 'development',
jwtExpiresIn: '1d'
};
src/config/database.js
const mongoose = require('mongoose');
const config = require('./config');
const logger = require('../utils/logger');
const connectDB = async () => {
try {
await mongoose.connect(config.mongoUri, {
useNewUrlParser: true,
useUnifiedTopology: true
});
logger.info('MongoDB connected successfully');
} catch (error) {
logger.error('MongoDB connection error:', error);
process.exit(1);
}
};
module.exports = connectDB;
3. Models Definition
src/models/user.model.js
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const config = require('../config/config');
const userSchema = new mongoose.Schema({
name: {
type: String,
required: [true, 'Name is required'],
trim: true,
minlength: 3,
maxlength: 50
},
email: {
type: String,
required: [true, 'Email is required'],
unique: true,
lowercase: true,
trim: true
},
password: {
type: String,
required: [true, 'Password is required'],
minlength: 6,
select: false
},
role: {
type: String,
enum: ['user', 'admin'],
default: 'user'
}
}, {
timestamps: true
});
// Pre-save middleware to hash password
userSchema.pre('save', async function(next) {
if (!this.isModified('password')) return next();
this.password = await bcrypt.hash(this.password, 12);
next();
});
// Instance methods
userSchema.methods.generateAuthToken = function() {
return jwt.sign(
{ id: this._id, role: this.role },
config.jwtSecret,
{ expiresIn: config.jwtExpiresIn }
);
};
userSchema.methods.comparePassword = async function(candidatePassword) {
return await bcrypt.compare(candidatePassword, this.password);
};
const User = mongoose.model('User', userSchema);
module.exports = User;
src/models/product.model.js
const mongoose = require('mongoose');
const productSchema = new mongoose.Schema({
name: {
type: String,
required: true,
trim: true
},
price: {
type: Number,
required: true,
min: 0
},
description: String,
category: {
type: String,
required: true
},
createdBy: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
required: true
}
}, {
timestamps: true
});
const Product = mongoose.model('Product', productSchema);
module.exports = Product;
4. Controllers
src/controllers/user.controller.js
const User = require('../models/user.model');
const { validateUser } = require('../utils/validators');
const logger = require('../utils/logger');
exports.register = async (req, res) => {
try {
const { error } = validateUser(req.body);
if (error) return res.status(400).json({ error: error.details[0].message });
const user = await User.create(req.body);
const token = user.generateAuthToken();
res.status(201).json({
status: 'success',
token,
data: { user }
});
} catch (error) {
logger.error('Registration error:', error);
res.status(400).json({
status: 'fail',
message: error.message
});
}
};
exports.login = async (req, res) => {
try {
const { email, password } = req.body;
const user = await User.findOne({ email }).select('+password');
if (!user || !(await user.comparePassword(password))) {
return res.status(401).json({
status: 'fail',
message: 'Invalid email or password'
});
}
const token = user.generateAuthToken();
res.json({
status: 'success',
token
});
} catch (error) {
logger.error('Login error:', error);
res.status(400).json({
status: 'fail',
message: error.message
});
}
};
5. Routes
src/routes/user.routes.js
const express = require('express');
const router = express.Router();
const userController = require('../controllers/user.controller');
const auth = require('../middleware/auth.middleware');
router.post('/register', userController.register);
router.post('/login', userController.login);
router.get('/profile', auth, userController.getProfile);
module.exports = router;
6. Middleware
src/middleware/auth.middleware.js
const jwt = require('jsonwebtoken');
const config = require('../config/config');
const User = require('../models/user.model');
module.exports = async (req, res, next) => {
try {
const token = req.headers.authorization?.replace('Bearer ', '');
if (!token) {
return res.status(401).json({
status: 'fail',
message: 'No token provided'
});
}
const decoded = jwt.verify(token, config.jwtSecret);
const user = await User.findById(decoded.id);
if (!user) {
return res.status(401).json({
status: 'fail',
message: 'User not found'
});
}
req.user = user;
next();
} catch (error) {
res.status(401).json({
status: 'fail',
message: 'Invalid token'
});
}
};
src/middleware/error.middleware.js
const logger = require('../utils/logger');
module.exports = (err, req, res, next) => {
logger.error(err.stack);
if (err.name === 'ValidationError') {
return res.status(400).json({
status: 'fail',
message: err.message
});
}
if (err.code === 11000) {
return res.status(400).json({
status: 'fail',
message: 'Duplicate field value'
});
}
res.status(err.status || 500).json({
status: 'error',
message: err.message || 'Internal server error'
});
};
7. Utils
src/utils/logger.js
const winston = require('winston');
const config = require('../config/config');
const logger = winston.createLogger({
level: config.nodeEnv === 'development' ? 'debug' : 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
transports: [
new winston.transports.File({ filename: 'logs/error.log', level: 'error' }),
new winston.transports.File({ filename: 'logs/combined.log' })
]
});
if (config.nodeEnv === 'development') {
logger.add(new winston.transports.Console({
format: winston.format.simple()
}));
}
module.exports = logger;
src/utils/validators.js
const Joi = require('joi');
exports.validateUser = (user) => {
const schema = Joi.object({
name: Joi.string().min(3).max(50).required(),
email: Joi.string().email().required(),
password: Joi.string().min(6).required(),
role: Joi.string().valid('user', 'admin')
});
return schema.validate(user);
};
exports.validateProduct = (product) => {
const schema = Joi.object({
name: Joi.string().required(),
price: Joi.number().min(0).required(),
description: Joi.string(),
category: Joi.string().required()
});
return schema.validate(product);
};
8. Main Application File
src/app.js
const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const config = require('./config/config');
const connectDB = require('./config/database');
const errorMiddleware = require('./middleware/error.middleware');
const userRoutes = require('./routes/user.routes');
const productRoutes = require('./routes/product.routes');
const logger = require('./utils/logger');
// Initialize express app
const app = express();
// Connect to MongoDB
connectDB();
// Middleware
app.use(helmet());
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// Routes
app.use('/api/users', userRoutes);
app.use('/api/products', productRoutes);
// Error handling
app.use(errorMiddleware);
// Start server
app.listen(config.port, () => {
logger.info(`Server running in ${config.nodeEnv} mode on port ${config.port}`);
});
// Handle unhandled promise rejections
process.on('unhandledRejection', (err) => {
logger.error('UNHANDLED REJECTION! Shutting down...');
logger.error(err.name, err.message);
process.exit(1);
});
Running the Application
- Install dependencies:
npm install
Set up your environment variables in
.env
Start the development server:
npm run dev
- For production:
npm start
Testing the API
Test the API endpoints using tools like Postman or curl:
# Register a new user
curl -X POST http://localhost:3000/api/users/register \
-H "Content-Type: application/json" \
-d '{"name": "John Doe", "email": "john@example.com", "password": "password123"}'
# Login
curl -X POST http://localhost:3000/api/users/login \
-H "Content-Type: application/json" \
-d '{"email": "john@example.com", "password": "password123"}'
This structured guide provides a complete setup for a Node.js and Mongoose application with proper organization, error handling, and security features. Each file has its specific responsibility, making the codebase maintainable and scalable.
Top comments (0)