Skip to main content

Node.js & Express – Dhisidda Barnaamijyo Backend oo Maamuli karo

· 10 min read
Shutiye Dev
Software Engineer & Educator

Node.js ayaa si weyn u beddelay horumarinta JavaScript-ka ee dhinaca server-ka, halka Express.js ay ka dhigto mid aad u fudud in laga dhiso API-yo iyo barnaamijyo shabakad awood badan. Aan u dhex galno dhisidda backend diyaar u ah wax-soo-saar!

🌟 Muxay Node.js & Express muhiim u yihiin ?

Node.js iyo Express waxay hoggaansan yihiin deegaanka backend ee JavaScript sababo dhowr ah dartood:

  • ⚡ Non-blocking I/O: Waxay maareeyaan kumannaan isku xirka is barbar socda
  • 🔄 JavaScript meel walba: Hal luqad ka shaqaysa frontend iyo backend
  • 📦 Deegaanka NPM: In ka badan 2 milyan oo xidhmooyin ah
  • 🚀 Horumar degdeg ah: Dhis oo qaadid si dhaqso ah
  • 💪 La kordhin karo: Ku habboon microservices iyo abka waqtiga-dhabta ah
  • 👥 Bulsho firfircoon: Taageero iyo agab fara badan

Goorma ayaa Node.js la isticmaalaa?

Ku habboon:

  • Barnaamijyo waqtiga-dhabta ah (chat, ciyaaro, wada-shaqeyn)
  • RESTful APIs iyo microservices
  • Single-page applications
  • Barnaamijyo qulqul (streaming)
  • IoT applications

Lama doorbido:

  • Hawlo CPU culus ah
  • Xisaab adag oo qalafsan

📦 Sida loo bilaabo

Shuruudaha Hore

# Hubi nooca Node.js (ugu yaraan 18)
node --version

# Hubi nooca npm
npm --version

# Haddii aan la rakibin, ka soo dejiso nodejs.org

Dejinta Mashruuca

# Abuur galka mashruuca
mkdir express-ecommerce-api
cd express-ecommerce-api

# Bilow npm project
npm init -y

# Ku rakib ku-tiirsanaanta
npm install express mongoose dotenv cors helmet morgan
npm install --save-dev nodemon

# Ku rakib agab horumarineed
npm install --save-dev @types/node @types/express

🏗️ Qaab-dhismeedka Mashruuca

Dhiso qaab sax ah oo la kordhin karo:

express-ecommerce-api/
├── src/
│ ├── config/
│ │ └── database.js
│ ├── controllers/
│ │ ├── productController.js
│ │ └── orderController.js
│ ├── models/
│ │ ├── Product.js
│ │ └── Order.js
│ ├── routes/
│ │ ├── productRoutes.js
│ │ └── orderRoutes.js
│ ├── middleware/
│ │ ├── errorHandler.js
│ │ └── validateRequest.js
│ ├── utils/
│ │ └── logger.js
│ └── app.js
├── .env
├── .gitignore
├── package.json
└── server.js

🎯 Dhisidda API E-Commerce ah

Aan dhisno API e-commerce oo dhamaystiran oo haya badeecooyin iyo amarro.

Tallaabada 1: Dejinta Deegaanka

Abuur .env:

# Dejinta server-ka
PORT=5000
NODE_ENV=development

# Kaydka xogta
MONGODB_URI=mongodb://localhost:27017/ecommerce
# Ama isticmaal MongoDB Atlas:
# MONGODB_URI=mongodb+srv://username:password@cluster.mongodb.net/ecommerce

# Sirta JWT
JWT_SECRET=your_super_secret_key_change_in_production

# Dejinta API
API_VERSION=v1

Abuur .gitignore:

node_modules/
.env
*.log
dist/
build/

Tallaabada 2: Dejinta Xiriirka Kaydka Xogta

Abuur src/config/database.js:

const mongoose = require('mongoose');

const connectDB = async () => {
try {
const conn = await mongoose.connect(process.env.MONGODB_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
});

console.log(`✅ MongoDB Connected: ${conn.connection.host}`);
} catch (error) {
console.error(`❌ Error: ${error.message}`);
process.exit(1);
}
};

module.exports = connectDB;

Tallaabada 3: Abuur Model-yada

Abuur src/models/Product.js:

const mongoose = require('mongoose');

const productSchema = new mongoose.Schema(
{
name: {
type: String,
required: [true, 'Product name is required'],
trim: true,
maxlength: [100, 'Product name cannot exceed 100 characters'],
},
description: {
type: String,
required: [true, 'Product description is required'],
maxlength: [2000, 'Description cannot exceed 2000 characters'],
},
price: {
type: Number,
required: [true, 'Product price is required'],
min: [0, 'Price cannot be negative'],
},
category: {
type: String,
required: [true, 'Product category is required'],
enum: ['Electronics', 'Clothing', 'Books', 'Home', 'Sports', 'Other'],
},
stock: {
type: Number,
required: true,
min: [0, 'Stock cannot be negative'],
default: 0,
},
images: [{
type: String,
}],
rating: {
type: Number,
default: 0,
min: 0,
max: 5,
},
numReviews: {
type: Number,
default: 0,
},
featured: {
type: Boolean,
default: false,
},
},
{
timestamps: true,
}
);

// Index for better search performance
productSchema.index({ name: 'text', description: 'text' });

module.exports = mongoose.model('Product', productSchema);

Abuur src/models/Order.js:

const mongoose = require('mongoose');

const orderSchema = new mongoose.Schema(
{
orderNumber: {
type: String,
required: true,
unique: true,
},
customer: {
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
phone: {
type: String,
required: true,
},
},
items: [{
product: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Product',
required: true,
},
quantity: {
type: Number,
required: true,
min: 1,
},
price: {
type: Number,
required: true,
},
}],
shippingAddress: {
street: String,
city: String,
state: String,
zipCode: String,
country: String,
},
totalAmount: {
type: Number,
required: true,
},
status: {
type: String,
enum: ['pending', 'processing', 'shipped', 'delivered', 'cancelled'],
default: 'pending',
},
paymentStatus: {
type: String,
enum: ['pending', 'completed', 'failed'],
default: 'pending',
},
},
{
timestamps: true,
}
);

// Generate order number before saving
orderSchema.pre('save', async function(next) {
if (!this.orderNumber) {
this.orderNumber = `ORD-${Date.now()}-${Math.floor(Math.random() * 1000)}`;
}
next();
});

module.exports = mongoose.model('Order', orderSchema);

Tallaabada 4: Abuur Controllers

Abuur src/controllers/productController.js:

const Product = require('../models/Product');

// @desc Get all products
// @route GET /api/v1/products
// @access Public
exports.getProducts = async (req, res, next) => {
try {
const { page = 1, limit = 10, category, search, sort } = req.query;

// Build query
const query = {};
if (category) query.category = category;
if (search) query.$text = { $search: search };

// Build sort
let sortOption = {};
if (sort === 'price_asc') sortOption.price = 1;
else if (sort === 'price_desc') sortOption.price = -1;
else if (sort === 'rating') sortOption.rating = -1;
else sortOption.createdAt = -1;

// Execute query with pagination
const products = await Product.find(query)
.sort(sortOption)
.limit(limit * 1)
.skip((page - 1) * limit)
.exec();

const count = await Product.countDocuments(query);

res.status(200).json({
success: true,
count: products.length,
total: count,
page: Number(page),
pages: Math.ceil(count / limit),
data: products,
});
} catch (error) {
next(error);
}
};

// @desc Get single product
// @route GET /api/v1/products/:id
// @access Public
exports.getProduct = async (req, res, next) => {
try {
const product = await Product.findById(req.params.id);

if (!product) {
return res.status(404).json({
success: false,
message: 'Product not found',
});
}

res.status(200).json({
success: true,
data: product,
});
} catch (error) {
next(error);
}
};

// @desc Create product
// @route POST /api/v1/products
// @access Private/Admin
exports.createProduct = async (req, res, next) => {
try {
const product = await Product.create(req.body);

res.status(201).json({
success: true,
data: product,
});
} catch (error) {
next(error);
}
};

// @desc Update product
// @route PUT /api/v1/products/:id
// @access Private/Admin
exports.updateProduct = async (req, res, next) => {
try {
const product = await Product.findByIdAndUpdate(
req.params.id,
req.body,
{
new: true,
runValidators: true,
}
);

if (!product) {
return res.status(404).json({
success: false,
message: 'Product not found',
});
}

res.status(200).json({
success: true,
data: product,
});
} catch (error) {
next(error);
}
};

// @desc Delete product
// @route DELETE /api/v1/products/:id
// @access Private/Admin
exports.deleteProduct = async (req, res, next) => {
try {
const product = await Product.findByIdAndDelete(req.params.id);

if (!product) {
return res.status(404).json({
success: false,
message: 'Product not found',
});
}

res.status(200).json({
success: true,
message: 'Product deleted successfully',
});
} catch (error) {
next(error);
}
};

// @desc Get featured products
// @route GET /api/v1/products/featured
// @access Public
exports.getFeaturedProducts = async (req, res, next) => {
try {
const products = await Product.find({ featured: true })
.limit(10)
.sort('-rating');

res.status(200).json({
success: true,
count: products.length,
data: products,
});
} catch (error) {
next(error);
}
};

Tallaabada 5: Abuur Routes

Abuur src/routes/productRoutes.js:

const express = require('express');
const {
getProducts,
getProduct,
createProduct,
updateProduct,
deleteProduct,
getFeaturedProducts,
} = require('../controllers/productController');

const router = express.Router();

router.get('/featured', getFeaturedProducts);
router.route('/')
.get(getProducts)
.post(createProduct);

router.route('/:id')
.get(getProduct)
.put(updateProduct)
.delete(deleteProduct);

module.exports = router;

Tallaabada 6: Middleware

Abuur src/middleware/errorHandler.js:

const errorHandler = (err, req, res, next) => {
let error = { ...err };
error.message = err.message;

// Log to console for dev
console.error(err);

// Mongoose bad ObjectId
if (err.name === 'CastError') {
const message = 'Resource not found';
error = { message, statusCode: 404 };
}

// Mongoose duplicate key
if (err.code === 11000) {
const message = 'Duplicate field value entered';
error = { message, statusCode: 400 };
}

// Mongoose validation error
if (err.name === 'ValidationError') {
const message = Object.values(err.errors).map(val => val.message);
error = { message, statusCode: 400 };
}

res.status(error.statusCode || 500).json({
success: false,
error: error.message || 'Server Error',
});
};

module.exports = errorHandler;

Tallaabada 7: Codsiga Ugu Weyn

Abuur src/app.js:

const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const morgan = require('morgan');
const errorHandler = require('./middleware/errorHandler');

// Import routes
const productRoutes = require('./routes/productRoutes');

const app = express();

// Middleware
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cors());
app.use(helmet());

// Logging
if (process.env.NODE_ENV === 'development') {
app.use(morgan('dev'));
}

// Health check
app.get('/health', (req, res) => {
res.status(200).json({
success: true,
message: 'Server is healthy',
timestamp: new Date().toISOString(),
});
});

// API routes
app.use('/api/v1/products', productRoutes);

// Root route
app.get('/', (req, res) => {
res.json({
message: 'Welcome to E-Commerce API',
version: '1.0.0',
endpoints: {
products: '/api/v1/products',
health: '/health',
},
});
});

// Error handler (must be last)
app.use(errorHandler);

// 404 handler
app.use((req, res) => {
res.status(404).json({
success: false,
message: 'Route not found',
});
});

module.exports = app;

Abuur server.js:

require('dotenv').config();
const app = require('./src/app');
const connectDB = require('./src/config/database');

const PORT = process.env.PORT || 5000;

// Connect to database
connectDB();

// Start server
const server = app.listen(PORT, () => {
console.log(`🚀 Server running in ${process.env.NODE_ENV} mode on port ${PORT}`);
});

// Handle unhandled promise rejections
process.on('unhandledRejection', (err) => {
console.log(`❌ Error: ${err.message}`);
server.close(() => process.exit(1));
});

Cusboonaysii package.json:

{
"name": "express-ecommerce-api",
"version": "1.0.0",
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js"
}
}

🚀 Socodsiinta Codsiga

# Habka horumarinta oo leh auto-reload
npm run dev

# Habka wax-soo-saarka
npm start

API-gaaga waxa laga heli doonaa http://localhost:5000

🧪 Tijaabinta API-ga

Abuurista Badeecad

curl -X POST http://localhost:5000/api/v1/products \
-H "Content-Type: application/json" \
-d '{
"name": "MacBook Pro 16-inch",
"description": "Powerful laptop for developers",
"price": 2499,
"category": "Electronics",
"stock": 50,
"featured": true
}'

Hel dhammaan Badeecooyinka

# Codsi aasaasi ah
curl http://localhost:5000/api/v1/products

# Iyadoo pagination ah
curl "http://localhost:5000/api/v1/products?page=1&limit=10"

# Ku shaandhee qayb
curl "http://localhost:5000/api/v1/products?category=Electronics"

# Raadi badeecooyin
curl "http://localhost:5000/api/v1/products?search=laptop"

# Ku kala saar qiimo
curl "http://localhost:5000/api/v1/products?sort=price_asc"

⚡ Astaamo Hormarsan

1. Hubinta Codsiyada (Request Validation)

Ku rakib validator:

npm install express-validator

Abuur middleware validation:

const { body, validationResult } = require('express-validator');

exports.validateProduct = [
body('name').trim().notEmpty().withMessage('Name is required'),
body('price').isNumeric().withMessage('Price must be a number'),
body('stock').isInt({ min: 0 }).withMessage('Stock must be non-negative'),

(req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
next();
},
];

2. Rate Limiting

npm install express-rate-limit
const rateLimit = require('express-rate-limit');

const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 daqiiqo
max: 100, // Xad 100 codsi IP kasta
message: 'Codsiyo badan, fadlan dib isku day goor dambe',
});

app.use('/api/', limiter);

3. Async Handler Wrapper

const asyncHandler = fn => (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(next);
};

// Isticmaal
exports.getProducts = asyncHandler(async (req, res) => {
const products = await Product.find();
res.json({ data: products });
});

4. File Upload

npm install multer
const multer = require('multer');

const storage = multer.diskStorage({
destination: './uploads/',
filename: (req, file, cb) => {
cb(null, `${Date.now()}-${file.originalname}`);
},
});

const upload = multer({ storage });

app.post('/upload', upload.single('image'), (req, res) => {
res.json({ filename: req.file.filename });
});

🔒 Hab-raacyada Amniga

1. Environment Variables

Waligaa ha commit-garin faylasha .env. Samee configs kala duwan deegaan kasta.

2. Nadiifinta Gelinta (Input Sanitization)

npm install express-mongo-sanitize
const mongoSanitize = require('express-mongo-sanitize');
app.use(mongoSanitize());

3. Ka-hortagga XSS

npm install xss-clean
const xss = require('xss-clean');
app.use(xss());

4. Cinwaannada Amniga HTTP

Waxaan hore u isticmaalnay helmet:

app.use(helmet());

📊 Hagaajinta Waxqabadka

1. Kaydinta (Caching) Redis

npm install redis
const redis = require('redis');
const client = redis.createClient();

// Cache middleware
const cache = (req, res, next) => {
const key = req.originalUrl;
client.get(key, (err, data) => {
if (data) {
return res.json(JSON.parse(data));
}
next();
});
};

2. Indexing ee kaydka xogta

// Gudaha model-kaaga
productSchema.index({ name: 1, category: 1 });

3. Cadaadinta jawaabaha

npm install compression
const compression = require('compression');
app.use(compression());

🚀 Daabacaadda (Deployment)

Adeegsiga PM2

npm install -g pm2

# Bilow app
pm2 start server.js --name "ecommerce-api"

# La soco
pm2 monit

# Dib u bilow
pm2 restart ecommerce-api

Docker

Abuur Dockerfile:

FROM node:18-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci --only=production

COPY . .

EXPOSE 5000

CMD ["node", "server.js"]

🎓 Qodobbo Muhiim ah

  • Express waa yar: Adigaa leh xakamaynta dhammaystiran ee qaab-dhismeedka
  • Qaabka Middleware: Awood badan oo dabacsanaan ah marka la farsameynayo codsiyada
  • Async/await: JavaScript casri ah oo loogu talagalay hawlo asynchronous ah
  • Mongoose: Hab hirgelin oo nadiif ah oo MongoDB ah
  • Amniga: Had iyo jeer hirgeli hab-raacyo amni
  • La kordhin karo: Node.js wuxuu ku fiican yahay maareynta isku xiryo badan oo isku mar ah

📚 Maxaa Xiga?

  • Ku dar xaqiijinta JWT
  • Kudar WebSocket si aad u hesho astaamo waqtiga-dhabta ah
  • Ku dar taageerada GraphQL
  • Ku xir albaabada lacag-bixinta (Stripe, PayPal)
  • Deji tijaabooyin Jest ah
  • Ku daabac AWS, Heroku, ama DigitalOcean

Node.js iyo Express waxay bixiyaan aasaas adag oo lagu dhiso APIs casri ah oo la kordhin karo. Bilow dhisidda API-yadaada maanta!


Ma rabtaa inaad wax badan ka barato? Ka eeg manhajka horumarinta backend ama nagala xiriir Twitter!