Yükleniyor...

Express.js Best Practices: Ölçeklenebilir Backend Mimarisi

Yazar: Burak Balkı | Kategori: DevOps | Okuma Süresi: 10 dk

Express.js ekosisteminde ölçeklenebilir, güvenli ve yüksek performanslı backend uygulamaları geliştirmek için kapsamlı best practices rehberi. Modern mimari,...

## Express.js Best Practices ve Modern Mimari Yaklaşımları **Express.js**, Node.js ekosisteminin en popüler ve esnek web çatısıdır. Ancak bu esneklik, yanlış yapılandırıldığında ölçeklenebilirlik ve güvenlik sorunlarına yol açabilir. Bu rehberde, kurumsal düzeyde bir uygulama geliştirmek için gereken **Express.js best practices** standartlarını, performans optimizasyonlarını ve DevOps süreçlerini detaylandıracağız. Uygulamanızın sürdürülebilir olması için sadece kod yazmak yeterli değildir; kodun nasıl organize edildiği, hataların nasıl yönetildiği ve güvenliğin nasıl sağlandığı kritik önem taşır. Modern backend dünyasında, bir uygulamanın başarısı verimlilik ve güvenliğe bağlıdır. ## Express.js Temel Kavramları ve Mimari Yapısı Express.js temelde bir **Middleware (Ara Yazılım)** zinciridir. Her istek (request) ve yanıt (response) döngüsü, belirli fonksiyonlar silsilesinden geçer. Mimariyi anlamak için şu temel bileşenleri bilmek gerekir: - **Application Instance:** Uygulamanın ana nesnesi. - **Middleware:** İstek ve yanıt nesnelerine erişimi olan fonksiyonlar. - **Routing:** URL yollarının belirli fonksiyonlara yönlendirilmesi. - **Error Handling:** Hata durumlarının merkezi bir noktadan yönetilmesi. ### Modern Bir Başlangıç: Express.js Kurulumu Profesyonel bir projeye başlarken bağımlılıkları yönetmek ve çevre değişkenlerini (environment variables) yapılandırmak ilk adımdır. ```javascript // app.js - Temel Yapılandırma const express = require('express'); const dotenv = require('dotenv'); dotenv.config(); // Çevre değişkenlerini yükle const app = express(); // JSON gövdesini ayrıştırmak için dahili middleware app.use(express.json({ limit: '10kb' })); const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(`Sunucu ${PORT} portunda çalışıyor.`); }); ``` ## Gelişmiş Proje Klasör Yapısı ve Organizasyonu Spagetti koddan kaçınmak için **Modüler Mimari** veya **MVC (Model-View-Controller)** yapısı tercih edilmelidir. DevOps süreçlerinde CI/CD boru hatlarının kodu kolayca test edebilmesi için mantıksal ayrım şarttır. | Klasör | Açıklama | | :--- | :--- | | `/controllers` | İstek mantığını yöneten fonksiyonlar | | `/models` | Veritabanı şemaları ve veri erişim katmanı | | `/routes` | API uç noktalarının tanımları | | `/middlewares` | Özel ara yazılımlar (Auth, Validation) | | `/services` | İş mantığının (Business Logic) bulunduğu katman | | `/utils` | Yardımcı fonksiyonlar ve sabitler | | `/tests` | Unit ve Integration testleri | ### Rotaların Modüler Hale Getirilmesi Kodun okunabilirliğini artırmak için rotaları ana dosyadan ayırın: ```javascript // routes/userRoutes.js const express = require('express'); const router = express.Router(); const userController = require('../controllers/userController'); router.route('/') .get(userController.getAllUsers) .post(userController.createUser); module.exports = router; ``` ## Middleware Kullanımı ve Özel Middleware Yazımı Middleware'ler, Express.js'in kalbidir. Her middleware'in `next()` fonksiyonunu çağırması veya bir yanıt dönmesi gerekir. **Best practice** olarak, her middleware tek bir sorumluluğa (Single Responsibility Principle) sahip olmalıdır. ### Özel Logger Middleware Örneği ```javascript // middlewares/logger.js const logger = (req, res, next) => { console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`); next(); }; module.exports = logger; ``` ## Güvenlik Standartları ve Express.js Güvenlik Önlemleri Express.js varsayılan olarak tüm güvenlik açıklarını kapatmaz. Uygulamanızı **OWASP** standartlarına uygun hale getirmek için şu adımları uygulamalısınız: 1. **Helmet.js Kullanımı:** HTTP başlıklarını güvenli hale getirir. 2. **Rate Limiting:** Brute-force saldırılarını engeller. 3. **Data Sanitization:** NoSQL Injection ve XSS saldırılarına karşı veriyi temizler. 4. **CORS Yapılandırması:** Sadece güvenilen kaynaklara izin verir. ### Güvenlik Katmanı Örneği ```javascript const helmet = require('helmet'); const rateLimit = require('express-rate-limit'); const mongoSanitize = require('express-mongo-sanitize'); const xss = require('xss-clean'); // HTTP başlıklarını koru app.use(helmet()); // İstek limitini belirle const limiter = rateLimit({ max: 100, windowMs: 60 * 60 * 1000, // 1 saat message: 'Çok fazla istek gönderildi, lütfen sonra tekrar deneyin.' }); app.use('/api', limiter); // Veri temizleme app.use(mongoSanitize()); // NoSQL Injection koruması app.use(xss()); // XSS koruması ``` ## Performans Optimizasyonu: Hız ve Verimlilik Teknikleri Node.js tek iş parçacıklı (single-threaded) olduğu için CPU yoğunluklu işlemler event loop'u bloke edebilir. Performansı artırmak için şu teknikler kullanılmalıdır: - **Gzip Sıkıştırma:** Yanıt boyutunu küçültür. - **Caching:** Redis gibi araçlarla sık erişilen verileri önbelleğe alın. - **Clustering:** Çok çekirdekli işlemcilerden yararlanın. - **Promise.all:** Bağımsız asenkron işlemleri paralel çalıştırın. ### Sıkıştırma ve Caching Uygulaması ```javascript const compression = require('compression'); // Yanıtları Gzip ile sıkıştır app.use(compression()); // Basit bir Cache Middleware mantığı const cache = (duration) => (req, res, next) => { // Burada Redis veya bellek içi cache kontrolü yapılabilir next(); }; ``` ## Hata Yönetimi (Error Handling) ve Merkezi Kontrol Uygulama genelinde `try-catch` bloklarını her yere yaymak yerine, merkezi bir hata yönetimi mekanizması kurun. Bu, kodun temiz kalmasını sağlar. ### Asenkron Hataları Yakalama ```javascript // utils/catchAsync.js module.exports = fn => { return (req, res, next) => { fn(req, res, next).catch(next); }; }; // controllers/userController.js kullanımı const catchAsync = require('../utils/catchAsync'); exports.getUser = catchAsync(async (req, res, next) => { const user = await User.findById(req.params.id); if (!user) return next(new AppError('Kullanıcı bulunamadı', 404)); res.status(200).json(user); }); ``` ## Veri Doğrulama ve Sanitizasyon Stratejileri İstek gövdelerini (request body) doğrulamak, veritabanı tutarlılığı için elzemdir. **Joi** veya **Zod** kütüphaneleri bu işlem için endüstri standardıdır. ```javascript const Joi = require('joi'); const validateUser = (data) => { const schema = Joi.object({ username: Joi.string().min(3).required(), email: Joi.string().email().required(), password: Joi.string().min(8).required() }); return schema.validate(data); }; ``` ## Log Yönetimi ve Monitoring Araçları `console.log` production ortamı için yetersizdir. **Winston** veya **Pino** gibi loglama kütüphaneleri kullanarak hataları dosyalara veya merkezi log sunucularına (ELK Stack, Datadog) aktarın. ```javascript const winston = require('winston'); const logger = winston.createLogger({ level: 'info', format: winston.format.json(), transports: [ new winston.transports.File({ filename: 'error.log', level: 'error' }), new winston.transports.File({ filename: 'combined.log' }), ], }); ``` ## Dockerize Express.js: DevOps Entegrasyonu Uygulamanın her ortamda aynı şekilde çalışması için Docker kullanımı standarttır. İşte optimize edilmiş bir `Dockerfile` örneği: ```dockerfile FROM node:18-alpine WORKDIR /app COPY package*.json ./ RUN npm install --only=production COPY . . EXPOSE 3000 CMD ["node", "server.js"] ``` ## Sık Yapılan Hatalar 1. **Sync Fonksiyonlar Kullanmak:** `fs.readFileSync` gibi fonksiyonlar event loop'u durdurur. Her zaman asenkron versiyonları kullanın. 2. **Hata Yönetimini İhmal Etmek:** Yakalanmayan hatalar (uncaught exceptions) sunucunun çökmesine neden olur. 3. **Güvenlik Başlıklarını Unutmak:** Helmet kullanmamak uygulamayı XSS'e açık hale getirir. 4. **Gereksiz Paket Kullanımı:** Her küçük işlem için kütüphane eklemek paket boyutunu ve güvenlik riskini artırır. ## Sık Sorulan Sorular (FAQ) **1. Express.js hala güncel mi?** Evet, Express.js Node.js dünyasının en çok kullanılan framework'üdür ve devasa bir topluluk desteğine sahiptir. **2. Neden `express-async-errors` kullanmalıyım?** Express 4.x sürümünde asenkron hatalar otomatik olarak `next(err)`'e aktarılmaz. Bu paket veya özel bir wrapper (catchAsync) bu süreci otomatikleştirir. **3. Body-parser kullanmalı mıyım?** Express 4.16.0 sürümünden itibaren `express.json()` ve `express.urlencoded()` dahili olarak gelmektedir, harici pakete gerek yoktur. **4. JWT (JSON Web Token) nerede saklanmalı?** En güvenli yöntem, XSS saldırılarından korunmak için `httpOnly` ve `secure` flag'li çerezler (cookies) içinde saklamaktır. **5. Uygulama canlıya alınırken hangi komut kullanılmalı?** `node app.js` yerine, süreç yönetimi ve otomatik yeniden başlatma için **PM2** gibi bir process manager kullanılmalıdır. ## Özet ve Sonuç Express.js ile profesyonel bir backend geliştirmek, sadece rotalar oluşturmaktan çok daha fazlasıdır. **Güvenlik**, **ölçeklenebilirlik** ve **hata yönetimi** prensiplerini uygulayarak, yüksek trafikli sistemlerde bile stabil çalışan uygulamalar inşa edebilirsiniz. Bu rehberde paylaşılan best practices yaklaşımları, modern DevOps süreçlerine uyumlu ve performans odaklı bir yapı kurmanıza yardımcı olacaktır.