Express.js''in gücü middleware pattern''inden gelir. Her HTTP isteği, pipeline üzerindeki fonksiyonların sırayla çalıştığı bir yolculuk geçirir. Bu yazı middleware''in nasıl çalıştığını, en kritik üç kategoriyi (auth, logging, error handling) ve kendi middleware''inizi nasıl yazacağınızı üretim seviyesi örneklerle gösterir.
Middleware Nedir?
İlgili rehberler: Yazılım geliştirme süreçleri · PostgreSQL optimizasyonu · Git ileri seviye komutlar · Redis nedir, nasıl kullanılır · Docker ile deploy
Middleware, (req, res, next) => {} imzasına sahip bir fonksiyondur. next() çağrıldığında pipeline bir sonraki middleware''e geçer; çağrılmazsa istek orada asılı kalır. next(err) ise pipeline''ı atlayıp error handler''a gider.
// En basit middleware
app.use((req, res, next) => {
req.startTime = Date.now();
next();
});
app.get('/', (req, res) => {
res.json({ took: Date.now() - req.startTime });
});
Request Logger
function requestLogger(req, res, next) {
const start = Date.now();
res.on('finish', () => {
const dur = Date.now() - start;
const level = res.statusCode >= 500 ? 'ERROR' : res.statusCode >= 400 ? 'WARN' : 'INFO';
console.log(`[${level}] ${req.method} ${req.originalUrl} ${res.statusCode} ${dur}ms`);
});
next();
}
app.use(requestLogger);
Authentication Middleware
const jwt = require('jsonwebtoken');
async function requireAuth(req, res, next) {
const header = req.headers.authorization || '';
const token = header.startsWith('Bearer ') ? header.slice(7) : null;
if (!token) return res.status(401).json({ error: 'Token required' });
try {
const payload = jwt.verify(token, process.env.JWT_SECRET, {
algorithms: ['HS256']
});
const user = await db.users.findByPk(payload.sub);
if (!user || !user.active) {
return res.status(401).json({ error: 'Invalid user' });
}
req.user = user;
next();
} catch (err) {
return res.status(401).json({ error: 'Invalid token' });
}
}
// Kullanım
app.get('/api/me', requireAuth, (req, res) => {
res.json(req.user);
});
Role-Based Authorization
function requireRole(...allowedRoles) {
return (req, res, next) => {
if (!req.user) return res.status(401).json({ error: 'Not authenticated' });
if (!allowedRoles.includes(req.user.role)) {
return res.status(403).json({ error: 'Insufficient permission' });
}
next();
};
}
// Zincirleme kullanım
app.delete('/api/users/:id', requireAuth, requireRole('admin'), async (req, res) => {
await db.users.destroy({ where: { id: req.params.id } });
res.status(204).end();
});
Error Handler
Express''te error handler (err, req, res, next) 4-argüman imzalı olan özel middleware''dir ve her zaman pipeline''ın sonunda tanımlanmalıdır.
class AppError extends Error {
constructor(status, message, code) {
super(message);
this.status = status;
this.code = code;
}
}
// Kullanım
if (!user) throw new AppError(404, 'User not found', 'USER_NOT_FOUND');
// Async route handler'larında error yakalama
function asyncHandler(fn) {
return (req, res, next) => Promise.resolve(fn(req, res, next)).catch(next);
}
app.get('/api/users/:id', asyncHandler(async (req, res) => {
const user = await db.users.findByPk(req.params.id);
if (!user) throw new AppError(404, 'User not found', 'USER_NOT_FOUND');
res.json(user);
}));
// Global error handler
app.use((err, req, res, next) => {
const status = err.status || 500;
const reqId = req.id || Date.now().toString(36);
if (status >= 500) {
console.error(`[${reqId}] ${err.stack}`);
}
res.status(status).json({
error: err.message || 'Internal server error',
code: err.code,
requestId: reqId
});
});
Validation Middleware
const { z } = require('zod');
function validate(schema) {
return (req, res, next) => {
const result = schema.safeParse(req.body);
if (!result.success) {
return res.status(400).json({
error: 'Validation failed',
issues: result.error.flatten()
});
}
req.body = result.data; // parsed + trimmed
next();
};
}
const createUserSchema = z.object({
email: z.string().email(),
password: z.string().min(8),
name: z.string().min(2).max(100)
});
app.post('/api/users', validate(createUserSchema), async (req, res) => {
// req.body artık validated ve typed
const user = await db.users.create(req.body);
res.status(201).json(user);
});
Rate Limit
const rateLimit = require('express-rate-limit');
// Global
app.use(rateLimit({ windowMs: 60000, max: 120 }));
// Hassas endpoint
app.use('/login', rateLimit({
windowMs: 900000, max: 5,
message: { error: 'Çok fazla giriş denemesi' }
}));
Pipeline Sıralaması
Middleware''lerin sırası çok önemli:
- Security (helmet, cors) — en başta
- Parser (express.json) — body''yi parse etmeden auth yapamazsın
- Logger — başarısız istekleri de görmek için erken
- Rate limit — kimlik doğrulamadan önce
- Authentication — route''lardan önce
- Routes
- 404 handler — tüm route''lardan sonra
- Error handler — en sonda
Modern Yazılım Geliştirme ve DevOps Pratikleri
Profesyonel yazılım geliştirme süreci üç pillar üzerine kuruludur: kaynak kontrolü (Git + GitHub/GitLab pull request akışı, code review zorunlu), CI/CD pipeline (otomatik test + lint + build + deploy), ve gözlemlenebilirlik (Sentry/Datadog/Grafana ile log, metric, trace toplama). Test piramidi (unit > integration > e2e) ile kod kalitesini garantilemek, mikroservis mimarisinde Docker container ve Kubernetes orkestrasyonu kullanmak, REST veya GraphQL API tasarımında OpenAPI/GraphQL Schema sözleşmesi tutmak modern standardlardır. Yazılım geliştirme yaşam döngüsü boyunca (gereksinim → tasarım → implementasyon → test → deploy → bakım) Agile/Scrum sprintleri 1-2 hafta, DevOps takımları sürekli teslim (continuous delivery) prensibiyle çalışır.
Express/Fastify ile API tasarımı, auth mimarisi ve production deploy için bize yazın