Kurumsal Düzeyde RESTful API'ler Tasarlamak: Node.js ve Express Kılavuzu
Modern web uygulaması ekosistemi; sağlam, ölçeklenebilir ve performanslı arka yüz mimarileri talep eder. Node.js, JavaScript'in her yerde bulunmasından yararlanırken, yüksek eşzamanlılık (concurrency) gerektiren senaryolarda öne çıkan bloke etmeyen (non-blocking) G/Ç (I/O) yetenekleri sağlayarak sunucu tarafı geliştirme için temel bir teknoloji haline gelmiştir. Bu kapsamlı kılavuz, Express framework'ü kullanarak kurumsal düzeyde RESTful API'ler oluşturmak için gerekli olan mimari ilkeleri, tasarım desenlerini ve mühendislik en iyi pratiklerini incelemektedir.
Node.js Çalışma Zamanı (Runtime) Mimarisi
Node.js, Google'ın V8 JavaScript motoru üzerinde çalışır ve kaynak kodu optimum yürütme performansı için yerel makine talimatlarına derler. Olay güdümlü (event-driven), asenkron mimarisi, geleneksel iş parçacığı (thread) tabanlı sunucu modellerinden temel olarak ayrılır:
Olay Döngüsü (Event Loop) Mekaniği
Node.js olay döngüsü, gelişmiş bir faz sistemi aracılığıyla bloke etmeyen operasyonları koordine eder:
Faz 1: Zamanlayıcılar (Timers) - setTimeout() ve setInterval() tarafından planlanan geri çağrıları (callbacks) yürütür.
Faz 2: Bekleyen Geri Çağrılar (Pending Callbacks) - Bir sonraki yinelemeye ertelenen G/Ç geri çağrılarını yürütür.
Faz 3: Boşta/Hazırlanma (Idle/Prepare) - Dahili sistem bakım operasyonları.
Faz 4: Yoklama (Poll) - Yeni G/Ç olaylarını alır; G/Ç geri çağrılarını yürütür.
Faz 5: Kontrol (Check) - setImmediate() geri çağrılarını yürütür.
Faz 6: Kapatma Geri Çağrıları (Close Callbacks) - Soket kapatma olaylarını yönetir.
Bu mimariyi anlamak, API yanıt sürelerini optimize etmek ve olay döngüsü tıkanması (event loop starvation) gibi yaygın tuzakları önlemek için son derece önemlidir.
Express Framework: Mimari Felsefe
Express, temel HTTP sunucu işlevselliği sağlarken karmaşık kararları ara yazılım (middleware) bileşenlerine devrederek minimalist bir tasarım felsefesini benimser. Bu mimari tercih birkaç stratejik avantaj sunar:
Ara Yazılım (Middleware) Deseni Uygulaması
const express = require('express');
const helmet = require('helmet');
const cors = require('cors');
const rateLimit = require('express-rate-limit');
const app = express();
// Güvenlik ara yazılımı yığını
app.use(helmet()); // HTTP başlıkları güvenliği
app.use(cors({
origin: process.env.ALLOWED_ORIGINS?.split(',') || ['http://localhost:3000'],
credentials: true
})); // Kökenler arası kaynak paylaşımı (CORS)
// DDoS koruması için istek sınırlama
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 dakika
max: 100, // Her bir IP'yi windowMs başına 100 istekle sınırla
message: 'Bu IP\'den çok fazla istek gönderildi, lütfen daha sonra tekrar deneyin.'
});
app.use('/api/', limiter);
// Gövde ayrıştırma ara yazılımı
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true, limit: '10mb' }));
RESTful Kaynak Tasarım İlkeleri
Richardson Olgunluk Modeli Uyumluluğu
Gerçek anlamda RESTful API'ler oluşturmak, dört seviyeli REST uygulamasını tanımlayan Richardson Olgunluk Modeli'ne bağlılık gerektirir:
Seviye 0: POX (Plain Old XML) Bataklığı
- Tüm operasyonlar için tek bir uç nokta
- RPC tarzı metodoloji
Seviye 1: Kaynaklar (Resources)
- Bireysel kaynaklar için belirgin URI'ler
/api/users,/api/articles
Seviye 2: HTTP Metotları (HTTP Verbs)
- GET, POST, PUT, DELETE, PATCH metotlarının doğru kullanımı
- Operasyon amacına göre anlamsal (semantic) karşılıklar
Seviye 3: Hipermedya Kontrolleri (HATEOAS)
- Yanıtın yönlendirici bağlantılar (links) içermesi
- Kendini belgeleyen API yapısı
Gelişmiş CRUD Operasyonları ve Hata Yönetimi
Üretime hazır API'ler, kapsamlı hata yönetimi ve doğrulama stratejileri gerektirir:
const { body, param, validationResult } = require('express-validator');
// Doğrulama ara yazılımı zinciri
const validateUser = [
body('email').isEmail().normalizeEmail(),
body('name').trim().isLength({ min: 2, max: 50 }),
body('password').isStrongPassword({ minLength: 12 }),
(req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({
errors: errors.array().map(err => ({
field: err.path,
message: err.msg,
value: err.value
}))
});
}
next();
}
];
// CREATE - Uygun durum kodları ile kaynak oluşturma
app.post('/api/users', validateUser, async (req, res) => {
try {
const user = await User.create({
...req.body,
password: await bcrypt.hash(req.body.password, 12)
});
// Location başlığı ile 201 Created döndür
res.location(`/api/users/${user._id}`);
res.status(201).json({
data: user,
meta: {
createdAt: user.createdAt,
requestId: req.id
}
});
} catch (error) {
if (error.code === 11000) {
return res.status(409).json({
error: 'Kaynak çakışması',
details: 'E-posta adresi zaten mevcut'
});
}
next(error); // Hata yöneticisine aktar
}
});
// READ - Sayfalama ve filtreleme ile koleksiyon getirme
app.get('/api/users', async (req, res) => {
try {
const page = parseInt(req.query.page) || 1;
const limit = parseInt(req.query.limit) || 20;
const skip = (page - 1) * limit;
const [users, total] = await Promise.all([
User.find().select('-password').skip(skip).limit(limit),
User.countDocuments()
]);
res.json({
data: users,
pagination: {
page,
limit,
total,
pages: Math.ceil(total / limit)
},
links: {
self: `/api/users?page=${page}&limit=${limit}`,
next: page < Math.ceil(total / limit) ? `/api/users?page=${page + 1}&limit=${limit}` : null,
prev: page > 1 ? `/api/users?page=${page - 1}&limit=${limit}` : null
}
});
} catch (error) {
next(error);
}
});
Ara Yazılım Mimari Desenleri
Kimlik Doğrulama & Yetkilendirme Ara Yazılımı
const jwt = require('jsonwebtoken');
// JWT doğrulama ara yazılımı
const authenticateToken = async (req, res, next) => {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN
if (!token) {
return res.status(401).json({ error: 'Kimlik doğrulaması gerekli' });
}
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded;
next();
} catch (error) {
return res.status(403).json({ error: 'Geçersiz veya süresi dolmuş token' });
}
};
// Rol tabanlı yetkilendirme
const authorizeRole = (...roles) => {
return (req, res, next) => {
if (!roles.includes(req.user.role)) {
return res.status(403).json({ error: 'Yetersiz yetki' });
}
next();
};
};
// Kullanım
app.get('/api/admin/users', authenticateToken, authorizeRole('admin'), getAllUsers);
Loglama & Gözlemlenebilirlik Ara Yazılımı
const morgan = require('morgan');
const { v4: uuidv4 } = require('uuid');
// İstek ID takibi (Request ID tracking)
app.use((req, res, next) => {
req.id = uuidv4();
res.setHeader('X-Request-ID', req.id);
next();
});
// Yapılandırılmış loglama (Structured logging)
app.use(morgan(':method :url :status :response-time ms - :res[content-length]', {
stream: {
write: (message) => {
console.log(JSON.stringify({
timestamp: new Date().toISOString(),
requestId: req.id,
method: req.method,
url: req.url,
status: res.statusCode,
responseTime: `${res.get('X-Response-Time')}ms`
}));
}
}
}));
Veritabanı Şema Tasarım Desenleri
Mongoose Şema Optimizasyonu
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
email: {
type: String,
required: true,
unique: true,
lowercase: true,
trim: true,
index: true,
match: [/^\S+@\S+\.\S+$/, 'Lütfen geçerli bir e-posta adresi girin']
},
name: {
type: String,
required: true,
trim: true,
minlength: 2,
maxlength: 50
},
role: {
type: String,
enum: ['user', 'admin', 'moderator'],
default: 'user'
},
isActive: {
type: Boolean,
default: true,
index: true
},
lastLoginAt: Date,
preferences: {
theme: { type: String, enum: ['light', 'dark'], default: 'dark' },
notifications: { type: Boolean, default: true }
}
}, {
timestamps: true, // createdAt ve updatedAt alanlarını otomatik ekler
toJSON: { virtuals: true },
toObject: { virtuals: true }
});
// Sorgu optimizasyonu için indeksler
userSchema.index({ name: 1, createdAt: -1 });
userSchema.index({ role: 1, isActive: 1 });
// Sanal alan eşleştirme (Virtual population)
userSchema.virtual('articles', {
ref: 'Article',
localField: '_id',
foreignField: 'authorId'
});
// Kayıt öncesi tetikleyiciler (Pre-save hooks)
userSchema.pre('save', function(next) {
if (this.isModified('email')) {
this.email = this.email.toLowerCase();
}
next();
});
module.exports = mongoose.model('User', userSchema);
Performans Optimizasyonu Stratejileri
Yanıt Sıkıştırma (Response Compression)
const compression = require('compression');
app.use(compression({
level: 6, // Sıkıştırma seviyesi (1-9)
threshold: 1024, // Yalnızca 1KB'tan büyük yanıtları sıkıştır
}));
Önbelleğe Alma Stratejileri
const NodeCache = require('node-cache');
const cache = new NodeCache({ stdTTL: 300 }); // Varsayılan 5 dakika
// Önbellek ara yazılımı
const cacheResponse = (duration) => {
return (req, res, next) => {
const key = `cache:${req.originalUrl}`;
const cachedData = cache.get(key);
if (cachedData) {
return res.json(cachedData);
}
// Yanıtı önbelleğe almak için res.json metodunu ez
const originalJson = res.json;
res.json = (data) => {
cache.set(key, data, duration);
return originalJson.call(res, data);
};
next();
};
};
// Kullanım
app.get('/api/users', cacheResponse(300), getUsers);
Sonuç: API Geliştirmede Mühendislik Mükemmeliyeti
Node.js ve Express ile kurumsal düzeyde RESTful API'ler tasarlamak, birden fazla mimari boyutta uzmanlık gerektirir: çalışma zamanı performans özellikleri, güvenlik sıkılaştırması, hata yönetimi stratejileri, veritabanı optimizasyonu ve gözlemlenebilirlik desenleri. Burada incelenen yapılar ve metodolojiler, yalnızca işlevsellikte değil aynı zamanda güvenilirlik, ölçeklenebilirlik ve sürdürülebilirlikte de öne çıkan API'ler tasarlamayı hedefleyen mühendislik ekipleri için bir temel sunmaktadır.
Bu mimari ilkelere öncelik veren kuruluşlar, entegrasyon hızını artırırken operasyonel ek yükü en aza indiren ve giderek daha fazla API odaklı hale gelen bir ekonomide rekabet avantajı sağlayan geliştirici deneyimleri sunacaklardır.
