Express.js ile Veritabanı Yönetimi: Kapsamlı [2026 Rehberi]
Yazar: Burak Balkı | Kategori: Database | Okuma Süresi: 38 dk
Bu kapsamlı 2026 rehberi, Express.js ile veritabanı yönetimini A'dan Z'ye ele alıyor. Temel kurulumdan ileri seviye optimizasyonlara, best practice'lerden ge...
## Express.js ile Veritabanı Yönetimi: Kapsamlı [2026 Rehberi]
Web uygulamalarının kalbi olan veritabanı etkileşimi, performans ve güvenliğin en kritik noktalarından biridir. Peki, 2026'da hala en popüler Node.js çatılarından biri olan Express.js ile veritabanı yönetimini en etkili şekilde nasıl yapabilirsiniz? Bu kapsamlı rehberde, Express.js projelerinizde veritabanı entegrasyonundan ileri seviye optimizasyonlara kadar A'dan Z'ye her şeyi ele alacağız. Amacımız, sizi bir Express.js ve veritabanı yönetimi uzmanına dönüştürerek, 2026'nın en güncel best practice'lerini uygulamalı olarak göstermektir.
### Express.js Nedir?
Express.js, Node.js için minimalist ve esnek bir web uygulama çatısıdır. Web ve mobil uygulamalar için sağlam bir API oluşturmayı sağlayan, geniş bir middleware ekosistemine sahip, hızlı ve performanslı bir backend çözümü sunar. 2026 itibarıyla hala çok aktif bir topluluğa ve yaygın kullanıma sahiptir, özellikle RESTful API geliştirmede tercih edilir.
Express.js, Node.js'in temel HTTP modülü üzerine inşa edilmiş olup, routing, middleware, template motorları gibi özellikler sunarak geliştiricilerin web uygulamalarını daha hızlı ve düzenli bir şekilde oluşturmasını sağlar. Bu esnek yapı, geliştiricilerin kendi ihtiyaçlarına göre özelleştirme yapmasına olanak tanır ve bu da onu 2026'da bile tercih edilen bir seçenek haline getirir.
### Neden Express.js Kullanmalısınız?
Express.js, 2026'da hala milyonlarca geliştirici tarafından tercih edilen bir backend çözümüdür. Bunun temel nedenleri şunlardır:
* **Hız ve Performans:** Node.js'in asenkron, olay tabanlı mimarisinden faydalanarak yüksek performanslı uygulamalar geliştirmenizi sağlar. Özellikle I/O yoğun uygulamalarda, Express.js ile veritabanı etkileşimleri oldukça hızlıdır.
* **Esneklik ve Minimalizm:** Çekirdek işlevselliği dışında gereksiz özellikler içermez, bu da projenizin ihtiyaçlarına göre modüller eklemenize olanak tanır. Bu minimalist yaklaşım, 2026'da dahi hafif ve özelleştirilebilir uygulamalar geliştirmek için idealdir.
* **Geniş Ekosistem ve Topluluk Desteği:** npm üzerinde binlerce hazır middleware ve kütüphane bulunur. Ayrıca, Stack Overflow, GitHub ve çeşitli forumlarda aktif ve yardımsever bir topluluğa sahiptir. 2026'da karşılaşabileceğiniz hemen her sorun için bir çözüm veya destek bulmanız mümkündür.
* **Ölçeklenebilirlik:** Küçük projelerden kurumsal seviyedeki mikroservislere kadar geniş bir yelpazede kullanılabilir. Node.js'in event loop mimarisi sayesinde, yüksek eşzamanlı bağlantıları yönetebilir.
* **RESTful API Geliştirme Kolaylığı:** Routing, HTTP metodları ve middleware kullanımı sayesinde RESTful API'ler oluşturmak oldukça pratiktir. 2026'da modern web ve mobil uygulamaların çoğu için bu birincil gereksinimdir.
**Kimler İçin Uygun?**
* Hızlı API geliştirmesi gerekenler.
* Tek sayfa uygulamalarının (SPA) backend'ini oluşturanlar.
* Mikroservis mimarileri düşünenler.
* JavaScript'i hem frontend hem de backend'de kullanmak isteyen (Full-Stack) geliştiriciler.
**Kimler İçin Uygun Değil?**
* Çok fazla yerleşik özellik ve yapılandırılmış bir çerçeve arayanlar (NestJS, AdonisJS gibi daha opinionated framework'ler tercih edilebilir).
* Daha düşük seviyeli performans optimizasyonları için C++, Go gibi dilleri tercih edenler.
### Express.js vs Alternatifler
2026'da Node.js ekosisteminde Express.js'e alternatif olabilecek bazı popüler çatılar bulunmaktadır. İşte Express.js'i diğerleriyle karşılaştıran bir tablo:
| Özellik | Express.js | Koa.js | NestJS |
| :----------------- | :------------------------------------------ | :-------------------------------------------- | :--------------------------------------------- |
| **Mimarisi** | Minimalist, unopinionated | Minimalist, asenkron (async/await) odaklı | Opinionated, modüler (Angular'dan ilham alan) |
| **Performans** | Yüksek, Node.js'in gücünü kullanır | Express.js'e benzer, daha modern middleware | Yüksek, TypeScript ile tip güvenliği sağlar |
| **Öğrenme Eğrisi** | Düşük, başlangıç için ideal | Orta, async/await ve Koa context'ine alışmak gerek | Yüksek, OOP, TypeScript ve mimari prensiplerini gerektirir |
| **Ekosistem** | Çok geniş, binlerce middleware | Daha küçük ama aktif, modern middleware'ler | Orta, kendi modülleri ve entegrasyonları var |
| **Topluluk** | Çok büyük ve aktif, 2026'da hala en büyüğü | Aktif ve büyüyen | Çok aktif ve büyüyen, kurumsal destekli |
| **Kurumsal Destek**| Yaygın kullanım, birçok şirket tercih ediyor | Daha çok bireysel projelerde | Kurumsal projelerde giderek artan popülarite |
| **Kullanım Alanı** | REST API, küçük/orta ölçekli uygulamalar | Modern API'ler, middleware kontrolü | Kurumsal API, mikroservis, büyük ölçekli uygulamalar |
**Yorum:** Express.js, basitlik ve esneklik arayanlar için 2026'da hala mükemmel bir seçimdir. Koa.js, daha modern asenkron programlama paradigmalarını benimserken, NestJS ise kurumsal düzeyde, ölçeklenebilir ve bakımı kolay uygulamalar geliştirmek isteyenler için kapsamlı bir çözüm sunar. Seçim, projenizin gereksinimlerine ve ekibinizin deneyim seviyesine bağlıdır.
### Kurulum ve İlk Adımlar
Express.js ile veritabanı etkileşimine başlamadan önce temel bir Express.js projesi kurmamız gerekiyor. Bu bölümde 2026'daki güncel Node.js ve npm sürümleriyle nasıl bir başlangıç yapacağınızı göstereceğim.
**Ön Gereksinimler:**
* Node.js (20.x LTS veya üzeri, 2026 itibarıyla önerilen sürüm)
* npm (Node.js ile birlikte gelir)
* Bir kod editörü (VS Code önerilir)
**Adım 1: Yeni Bir Express.js Projesi Oluşturma**
Boş bir dizin oluşturun ve içine girin:
```bash
mkdir express-db-app-2026
cd express-db-app-2026
```
Ardından, `package.json` dosyasını başlatın. Bu dosya projenizin bağımlılıklarını ve meta verilerini içerecektir:
```bash
npm init -y
```
**Adım 2: Express.js Bağımlılığını Ekleme**
Şimdi Express.js'i projenize yükleyin:
```bash
npm install express
```
**Adım 3: İlk Express.js Sunucusunu Oluşturma**
`index.js` adında bir dosya oluşturun ve içine aşağıdaki kodu ekleyin:
```javascript
// index.js
const express = require('express');
const app = express();
const port = 3000;
app.get('/', (req, res) => {
res.send('Merhaba Express.js ve Veritabanı! 2026');
});
app.listen(port, () => {
console.log(`Express uygulaması http://localhost:${port} adresinde çalışıyor!`);
});
```
**Adım 4: Uygulamayı Çalıştırma**
Terminalde aşağıdaki komutu çalıştırın:
```bash
node index.js
```
Tarayıcınızda `http://localhost:3000` adresine gittiğinizde "Merhaba Express.js ve Veritabanı! 2026" mesajını görmelisiniz. Tebrikler, ilk Express.js uygulamanız 2026'da başarıyla çalışıyor!
### Temel Kullanım ve Örnekler
Express.js ile veritabanı etkileşimleri genellikle bir ORM (Object-Relational Mapper) veya ODM (Object-Document Mapper) kütüphanesi aracılığıyla yapılır. Bu bölümde hem PostgreSQL (SQL) hem de MongoDB (NoSQL) için temel CRUD (Create, Read, Update, Delete) operasyonlarını ele alacağız. 2026'da bu iki veritabanı türü de oldukça popülerdir.
**Örnek 1: PostgreSQL ile Temel CRUD (pg kütüphanesi)**
PostgreSQL için `pg` kütüphanesini kullanacağız. İlk olarak yükleyelim:
```bash
npm install pg
```
`db.js` adında bir veritabanı bağlantı dosyası oluşturalım:
```javascript
// db.js
const { Pool } = require('pg');
const pool = new Pool({
user: 'your_user',
host: 'localhost',
database: 'your_database_name',
password: 'your_password',
port: 5432,
});
module.exports = pool;
```
Ardından `index.js` dosyamızı güncelleyerek bir `todos` API'si oluşturalım:
```javascript
// index.js (PostgreSQL Entegrasyonu)
const express = require('express');
const pool = require('./db'); // db.js dosyamızı import ettik
const app = express();
const port = 3000;
app.use(express.json()); // JSON body parsing için
// Tüm görevleri getir
app.get('/todos', async (req, res) => {
try {
const allTodos = await pool.query('SELECT * FROM todos ORDER BY id ASC');
res.json(allTodos.rows);
} catch (err) {
console.error(err.message);
res.status(500).send('Sunucu Hatası 2026');
}
});
// Yeni görev ekle
app.post('/todos', async (req, res) => {
try {
const { description } = req.body;
const newTodo = await pool.query(
'INSERT INTO todos (description) VALUES($1) RETURNING *',
[description]
);
res.json(newTodo.rows[0]);
} catch (err) {
console.error(err.message);
res.status(500).send('Sunucu Hatası 2026');
}
});
// Bir görevi güncelle
app.put('/todos/:id', async (req, res) => {
try {
const { id } = req.params;
const { description } = req.body;
const updateTodo = await pool.query(
'UPDATE todos SET description = $1 WHERE id = $2 RETURNING *',
[description, id]
);
if (updateTodo.rows.length === 0) {
return res.status(404).json('Görev bulunamadı 2026');
}
res.json(updateTodo.rows[0]);
} catch (err) {
console.error(err.message);
res.status(500).send('Sunucu Hatası 2026');
}
});
// Bir görevi sil
app.delete('/todos/:id', async (req, res) => {
try {
const { id } = req.params;
const deleteTodo = await pool.query('DELETE FROM todos WHERE id = $1 RETURNING *', [id]);
if (deleteTodo.rows.length === 0) {
return res.status(404).json('Görev bulunamadı 2026');
}
res.json('Görev başarıyla silindi 2026');
} catch (err) {
console.error(err.message);
res.status(500).send('Sunucu Hatası 2026');
}
});
app.listen(port, () => {
console.log(`PostgreSQL destekli Express uygulaması http://localhost:${port} adresinde çalışıyor!`);
});
```
**Örnek 2: MongoDB ile Temel CRUD (Mongoose ODM)**
MongoDB için `mongoose` ODM'sini kullanacağız. Yükleyelim:
```bash
npm install mongoose
```
`db.js` dosyamızı MongoDB için güncelleyelim (veya `mongodb.js` adında yeni bir dosya oluşturalım):
```javascript
// mongodb.js
const mongoose = require('mongoose');
const connectDB = async () => {
try {
const conn = await mongoose.connect('mongodb://localhost:27017/expressdb2026', {
useNewUrlParser: true,
useUnifiedTopology: true,
// useCreateIndex: true, // Mongoose 6.x ve 2026'da artık gerekli değil
// useFindAndModify: false // Mongoose 6.x ve 2026'da artık gerekli değil
});
console.log(`MongoDB Bağlantısı Başarılı: ${conn.connection.host}`);
} catch (error) {
console.error(`MongoDB Bağlantı Hatası: ${error.message}`);
process.exit(1); // Uygulamayı sonlandır
}
};
module.exports = connectDB;
```
Bir `Todo` modeli oluşturalım (`models/Todo.js`):
```javascript
// models/Todo.js
const mongoose = require('mongoose');
const todoSchema = new mongoose.Schema({
description: {
type: String,
required: true,
trim: true,
},
completed: {
type: Boolean,
default: false,
},
createdAt: {
type: Date,
default: Date.now,
},
});
module.exports = mongoose.model('Todo', todoSchema);
```
`index.js` dosyamızı MongoDB entegrasyonu için güncelleyelim:
```javascript
// index.js (MongoDB Entegrasyonu)
const express = require('express');
const connectDB = require('./mongodb'); // MongoDB bağlantı dosyamız
const Todo = require('./models/Todo'); // Todo modelimiz
const app = express();
const port = 3000;
connectDB(); // MongoDB'ye bağlan
app.use(express.json());
// Tüm görevleri getir
app.get('/todos', async (req, res) => {
try {
const todos = await Todo.find({});
res.json(todos);
} catch (err) {
console.error(err.message);
res.status(500).send('Sunucu Hatası 2026');
}
});
// Yeni görev ekle
app.post('/todos', async (req, res) => {
try {
const todo = new Todo(req.body);
await todo.save();
res.status(201).json(todo);
} catch (err) {
console.error(err.message);
res.status(400).send('Geçersiz istek 2026');
}
});
// Bir görevi ID ile getir
app.get('/todos/:id', async (req, res) => {
try {
const todo = await Todo.findById(req.params.id);
if (!todo) {
return res.status(404).json({ msg: 'Görev bulunamadı 2026' });
}
res.json(todo);
} catch (err) {
console.error(err.message);
if (err.kind === 'ObjectId') {
return res.status(400).json({ msg: 'Geçersiz ID formatı 2026' });
}
res.status(500).send('Sunucu Hatası 2026');
}
});
// Bir görevi güncelle
app.put('/todos/:id', async (req, res) => {
try {
const todo = await Todo.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true });
if (!todo) {
return res.status(404).json({ msg: 'Görev bulunamadı 2026' });
}
res.json(todo);
} catch (err) {
console.error(err.message);
if (err.kind === 'ObjectId') {
return res.status(400).json({ msg: 'Geçersiz ID formatı 2026' });
}
res.status(500).send('Sunucu Hatası 2026');
}
});
// Bir görevi sil
app.delete('/todos/:id', async (req, res) => {
try {
const todo = await Todo.findByIdAndDelete(req.params.id);
if (!todo) {
return res.status(404).json({ msg: 'Görev bulunamadı 2026' });
}
res.json({ msg: 'Görev başarıyla silindi 2026' });
} catch (err) {
console.error(err.message);
if (err.kind === 'ObjectId') {
return res.status(400).json({ msg: 'Geçersiz ID formatı 2026' });
}
res.status(500).send('Sunucu Hatası 2026');
}
});
app.listen(port, () => {
console.log(`MongoDB destekli Express uygulaması http://localhost:${port} adresinde çalışıyor!`);
});
```
> **Pro Tip (2026):** Gerçek dünya projelerinde, veritabanı bağlantı bilgilerini doğrudan kodda tutmak yerine `.env` dosyaları kullanarak ortam değişkenleri aracılığıyla yönetmek güvenlik açısından kritik öneme sahiptir. Bunun için `dotenv` kütüphanesini kullanabilirsiniz.
### İleri Seviye Teknikler
Express.js ile veritabanı etkileşimlerini daha sağlam, ölçeklenebilir ve bakımı kolay hale getirmek için 2026'da kullanabileceğiniz bazı ileri seviye teknikler ve tasarım desenleri şunlardır:
1. **Repository Deseni (Repository Pattern):** Veritabanı sorgularını ve iş mantığını ayırarak kodun daha modüler olmasını sağlar. Bu sayede veritabanı teknolojisini değiştirmek istediğinizde (örneğin PostgreSQL'den MongoDB'ye geçiş), sadece repository katmanını güncellemeniz yeterli olur.
```javascript
// repositories/todoRepository.js (Örnek PostgreSQL için)
const pool = require('../db');
class TodoRepository {
async findAll() {
const result = await pool.query('SELECT * FROM todos ORDER BY id ASC');
return result.rows;
}
async findById(id) {
const result = await pool.query('SELECT * FROM todos WHERE id = $1', [id]);
return result.rows[0];
}
async create(description) {
const result = await pool.query('INSERT INTO todos (description) VALUES($1) RETURNING *', [description]);
return result.rows[0];
}
async update(id, description) {
const result = await pool.query('UPDATE todos SET description = $1 WHERE id = $2 RETURNING *', [description, id]);
return result.rows[0];
}
async delete(id) {
const result = await pool.query('DELETE FROM todos WHERE id = $1 RETURNING *', [id]);
return result.rows[0];
}
}
module.exports = new TodoRepository();
```
```javascript
// routes/todoRoutes.js (Repository kullanan Express rotası)
const express = require('express');
const router = express.Router();
const todoRepository = require('../repositories/todoRepository');
router.get('/', async (req, res) => {
try {
const todos = await todoRepository.findAll();
res.json(todos);
} catch (err) {
console.error(err.message);
res.status(500).send('Sunucu Hatası 2026');
}
});
// Diğer CRUD operasyonları benzer şekilde eklenebilir...
module.exports = router;
```
2. **Veritabanı İşlemlerinde İşlem Yönetimi (Transactions):** Birden fazla veritabanı operasyonunun ya hep birlikte başarılı olması ya da hiç olmaması gereken durumlarda (örneğin para transferi), transaction'lar kritik öneme sahiptir. 2026'da güvenilir uygulamalar için vazgeçilmezdir.
```javascript
// transactionExample.js (PostgreSQL için)
const pool = require('./db');
async function transferMoney(senderId, receiverId, amount) {
const client = await pool.connect();
try {
await client.query('BEGIN'); // İşlemi başlat
// Göndericiden para düş
await client.query('UPDATE accounts SET balance = balance - $1 WHERE id = $2', [amount, senderId]);
// Alıcıya para ekle
await client.query('UPDATE accounts SET balance = balance + $1 WHERE id = $2', [amount, receiverId]);
await client.query('COMMIT'); // İşlemi onayla
console.log('Para transferi başarılı 2026');
} catch (e) {
await client.query('ROLLBACK'); // Hata durumunda geri al
console.error('Para transferi başarısız oldu:', e.message);
throw e; // Hatayı yukarı fırlat
} finally {
client.release(); // Bağlantıyı geri havuzuna bırak
}
}
// Kullanım örneği
// transferMoney(1, 2, 100).catch(console.error);
```
3. **Veritabanı Bağlantı Havuzu (Connection Pooling):** Her istek için yeni bir veritabanı bağlantısı açmak yerine, önceden açılmış bağlantıları yeniden kullanmak performansı önemli ölçüde artırır. Yukarıdaki `pg` örneğinde `Pool` objesi bunu otomatik olarak yapar. Mongoose da kendi bağlantı havuzunu yönetir.
4. **Veri Validasyonu (Data Validation):** Veritabanına kaydedilmeden önce verilerin doğru formatta ve geçerli olduğundan emin olmak için validasyon middleware'leri kullanın. `joi` veya `express-validator` gibi kütüphaneler 2026'da yaygın olarak kullanılır.
```bash
npm install joi
```
```javascript
// middleware/validateTodo.js
const Joi = require('joi');
const todoSchema = Joi.object({
description: Joi.string().min(3).max(255).required(),
completed: Joi.boolean().optional(),
});
const validateTodo = (req, res, next) => {
const { error } = todoSchema.validate(req.body);
if (error) {
return res.status(400).json({ message: error.details[0].message });
}
next();
};
module.exports = validateTodo;
```
```javascript
// routes/todoRoutes.js (validasyon middleware'i kullanımı)
const validateTodo = require('../middleware/validateTodo');
// ...
router.post('/', validateTodo, async (req, res) => {
// ... create todo
});
```
### Best Practices & Anti-Patterns
Express.js ile veritabanı etkileşimlerinde 2026'da dikkat etmeniz gereken en iyi uygulamalar ve kaçınmanız gereken anti-pattern'lar:
* ✅ **Ortam Değişkenleri Kullanın:** Veritabanı kimlik bilgilerini `.env` dosyalarında tutun ve `dotenv` gibi kütüphanelerle erişin. Asla doğrudan kodda bırakmayın.
* ❌ **Kimlik Bilgilerini Koda Gömme:** `db.js` dosyasında `user: 'root', password: '123'` gibi bilgileri doğrudan yazmak büyük bir güvenlik açığıdır.
* ✅ **Asenkron İşlemler İçin `async/await` Kullanın:** Veritabanı operasyonları asenkron olduğu için `async/await` yapısını kullanarak kodunuzu daha okunabilir ve yönetilebilir hale getirin. Callback cehenneminden kaçının.
* ❌ **Callback Cehennemi:** İç içe geçmiş callback'ler, kodun okunabilirliğini ve bakımını zorlaştırır, özellikle 2026'da modern JavaScript'te yeri yoktur.
* ✅ **Veritabanı Bağlantı Havuzu Kullanın:** Her istek için yeni bir bağlantı açmak yerine, `pg.Pool` veya Mongoose'un dahili bağlantı havuzunu kullanarak performansı artırın ve kaynak tüketimini azaltın.
* ❌ **Her İstekte Yeni Bağlantı:** Her API çağrısında veritabanına yeniden bağlanmak, uygulamanızın performansını ciddi şekilde düşürür ve veritabanı sunucusunu yorar.
* ✅ **Veri Validasyonu Uygulayın:** Kullanıcıdan gelen tüm verileri veritabanına kaydetmeden önce doğrulayın. Bu, hem güvenlik açıklarını (SQL Injection, XSS) önler hem de veri bütünlüğünü sağlar.
* ❌ **Ham Kullanıcı Girişini Doğrudan Sorguya Dahil Etme:** Kullanıcıdan gelen verileri doğrudan SQL sorgularına `+` operatörü ile eklemek, SQL Injection saldırılarına davetiye çıkarır. Prepared statement'lar veya ORM/ODM'ler kullanın.
* ✅ **Error Handling Middleware Kullanın:** Uygulama genelinde hataları yakalamak ve merkezi bir şekilde yönetmek için özel bir hata işleme middleware'i tanımlayın.
* ❌ **Her Rotada Ayrı Ayrı `try-catch`:** Her bir rota handler'ında ayrı ayrı `try-catch` blokları kullanmak yerine, bir hata işleme middleware'i ile kod tekrarını azaltın.
* ✅ **Modüler Rota Yapısı:** Rotları ve veritabanı etkileşimlerini ayrı dosyalarda (örneğin `routes/`, `models/`, `repositories/`) tutarak projenizin yapısını düzenli tutun.
* ❌ **Tüm Kod Tek Bir Dosyada:** Tüm Express.js ve veritabanı kodunu tek bir `index.js` dosyasında toplamak, projenin büyümesiyle birlikte yönetilemez hale gelir.
* ✅ **Veritabanı İşlemlerinde İşlem Yönetimi (Transactions):** Birden fazla bağımlı veritabanı operasyonunu tek bir atomik birim olarak ele alın, böylece veri tutarlılığını sağlayın. Özellikle 2026'daki finansal veya kritik işlemler için zorunludur.
* ❌ **Bağımlı Operasyonları Ayrı Ayrı Çalıştırma:** Bir işlemin başarısız olması durumunda diğerlerinin geri alınmaması veri tutarsızlığına yol açar.
### Yaygın Hatalar ve Çözümleri
Express.js ve veritabanı entegrasyonu sırasında 2026'da karşılaşabileceğiniz bazı yaygın hatalar ve bunların çözümleri:
1. **Hata:** `Error: connect ECONNREFUSED 127.0.0.1:5432` (PostgreSQL) veya `MongooseServerSelectionError: connect ECONNREFUSED 127.0.0.1:27017` (MongoDB)
* **Sebep:** Veritabanı sunucusuna bağlanılamıyor. Sunucu çalışmıyor, yanlış port kullanılıyor veya güvenlik duvarı engelliyor olabilir.
* **Çözüm:** Veritabanı sunucunuzun çalıştığından emin olun (örneğin, `sudo service postgresql start` veya MongoDB için `mongod` komutu). Bağlantı bilgilerini (host, port, kullanıcı adı, şifre) kontrol edin. Gerekirse güvenlik duvarı ayarlarınızı gözden geçirin.
2. **Hata:** `(node:XXXXX) UnhandledPromiseRejectionWarning: ...`
* **Sebep:** Asenkron bir işlemde (veritabanı sorgusu gibi) yakalanmayan bir Promise hatası oluştu. Genellikle `async/await` bloklarında `try-catch` kullanılmadığında meydana gelir.
* **Çözüm:** Tüm `await` çağrılarını bir `try-catch` bloğu içine alın. Ayrıca, Express.js'te bu tür hataları merkezi olarak yakalamak için bir hata işleme middleware'i kullanın (`app.use((err, req, res, next) => { ... })`). 2026'da bu, standart bir uygulamadır.
3. **Hata:** `CastError: Cast to ObjectId failed for value "invalidId" at path "_id"` (MongoDB Mongoose)
* **Sebep:** MongoDB'de bir belgeyi sorgularken veya güncellerken geçersiz bir ObjectId formatı kullanıldı.
* **Çözüm:** `req.params.id` gibi yerlerden gelen ID'lerin geçerli bir MongoDB ObjectId formatında olduğundan emin olun. Gerekirse validasyon yapın veya hatayı kullanıcıya uygun bir mesajla döndürün (`res.status(400).json({ msg: 'Geçersiz ID formatı' });`).
4. **Hata:** `error: column "description" does not exist` (PostgreSQL)
* **Sebep:** SQL sorgunuzda belirtilen sütun adı veritabanı tablonuzda bulunmuyor veya yanlış yazılmış.
* **Çözüm:** Veritabanı şemanızı kontrol edin ve sorgunuzdaki sütun adının doğru olduğundan emin olun. Büyük/küçük harf duyarlılığına dikkat edin veya sorguyu yeniden yazın.
### Performans Optimizasyonu
Express.js uygulamalarınızda veritabanı performansını 2026'da en üst düzeye çıkarmak için uygulayabileceğiniz stratejiler:
1. **Veritabanı İndeksleme:** Sık sorgulanan sütunlara indeks eklemek, okuma operasyonlarının hızını önemli ölçüde artırır. Örneğin, `todos` tablosunda `description` veya `createdAt` sütunlarına indeks eklemek, filtreleme ve sıralama işlemlerini hızlandırır.
```sql
-- PostgreSQL indeks örneği
CREATE INDEX idx_todos_description ON todos (description);
CREATE INDEX idx_todos_createdat ON todos (createdAt);
```
2. **Sorgu Optimizasyonu:** N+1 sorgu problemini çözün, gereksiz join'lerden kaçının, sadece ihtiyacınız olan sütunları seçin (`SELECT column1, column2 FROM ...` yerine `SELECT * FROM ...`). ORM kullanıyorsanız, `eager loading` (ilişkili verileri tek sorguda getirme) yöntemlerini kullanın.
3. **Caching (Önbellekleme):** Sık erişilen ve nadiren değişen verileri Redis veya Memcached gibi bir önbellek sisteminde tutarak veritabanı yükünü azaltın. Bu, özellikle 2026'da yüksek trafikli API'ler için kritik bir optimizasyondur.
```bash
npm install redis
```
```javascript
// Caching örneği (Express.js middleware)
const redis = require('redis');
const client = redis.createClient({ url: 'redis://localhost:6379' });
client.connect();
const cacheMiddleware = (req, res, next) => {
const key = req.originalUrl;
client.get(key, (err, data) => {
if (err) throw err;
if (data !== null) {
res.send(JSON.parse(data));
} else {
res.sendResponse = res.send;
res.send = (body) => {
client.setEx(key, 3600, JSON.stringify(body)); // 1 saat önbellekte tut
res.sendResponse(body);
};
next();
}
});
};
// Kullanım: app.get('/todos', cacheMiddleware, async (req, res) => { ... });
```
4. **Veritabanı Bağlantı Havuzu Yapılandırması:** `pg.Pool` veya Mongoose bağlantı ayarlarında `max` bağlantı sayısı, `idleTimeoutMillis` gibi parametreleri uygulamanızın yüküne göre optimize edin.
5. **Asenkron İşlemler ve Non-Blocking I/O:** Node.js'in doğası gereği asenkron çalışmasından tam olarak yararlanın. Veritabanı operasyonlarını bloke etmeyin; `async/await` kullanarak uygulamanızın diğer istekleri işlemeye devam etmesini sağlayın.
6. **Profiling ve Monitoring:** `New Relic`, `Prometheus` veya `Grafana` gibi araçlarla uygulamanızın ve veritabanınızın performansını izleyin. Hangi sorguların yavaş çalıştığını, hangi rotaların darboğaz oluşturduğunu tespit edin ve optimize edin. 2026'da bu tür araçlar, üretim ortamındaki uygulamaların sağlığı için vazgeçilmezdir.
### Gerçek Dünya Proje Örneği (Mini Proje)
Bu bölümde, Express.js ve MongoDB kullanarak basit bir Blog API'si oluşturan küçük bir projenin dosya yapısını ve temel kodlarını inceleyeceğiz. Bu proje, 2026'da modern bir backend uygulamasının nasıl yapılandırılabileceğine dair pratik bir örnek sunacaktır.
**Proje Yapısı:**
```
express-blog-api-2026/
├── .env
├── package.json
├── index.js
├── config/
│ └── db.js
├── models/
│ └── Post.js
├── routes/
│ └── posts.js
├── middleware/
│ └── errorHandler.js
└── node_modules/
```
**1. `.env` (Ortam Değişkenleri)**
```dotenv
PORT=5000
MONGO_URI=mongodb://localhost:27017/blogapi2026
```
**2. `package.json`**
```json
{
"name": "express-blog-api-2026",
"version": "1.0.0",
"description": "Express.js ve MongoDB ile Blog API'si 2026",
"main": "index.js",
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js"
},
"dependencies": {
"dotenv": "^16.4.5",
"express": "^4.18.3",
"mongoose": "^8.2.1"
},
"devDependencies": {
"nodemon": "^3.1.0"
}
}
```
**3. `config/db.js` (Veritabanı Bağlantısı)**
```javascript
// config/db.js
const mongoose = require('mongoose');
const connectDB = async () => {
try {
const conn = await mongoose.connect(process.env.MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
console.log(`MongoDB Bağlantısı Başarılı: ${conn.connection.host} (2026)`);
} catch (error) {
console.error(`MongoDB Bağlantı Hatası: ${error.message}`);
process.exit(1);
}
};
module.exports = connectDB;
```
**4. `models/Post.js` (Post Modeli)**
```javascript
// models/Post.js
const mongoose = require('mongoose');
const postSchema = new mongoose.Schema({
title: {
type: String,
required: true,
trim: true,
minlength: 5,
maxlength: 100,
},
content: {
type: String,
required: true,
minlength: 10,
},
author: {
type: String,
required: true,
default: 'Anonim',
},
createdAt: {
type: Date,
default: Date.now,
},
updatedAt: {
type: Date,
default: Date.now,
},
});
// Her güncellemede 'updatedAt' alanını otomatik set et
postSchema.pre('save', function(next) {
this.updatedAt = Date.now();
next();
});
module.exports = mongoose.model('Post', postSchema);
```
**5. `routes/posts.js` (Rota Tanımları)**
```javascript
// routes/posts.js
const express = require('express');
const router = express.Router();
const Post = require('../models/Post');
// Tüm blog yazılarını getir
router.get('/', async (req, res) => {
try {
const posts = await Post.find().sort({ createdAt: -1 });
res.json(posts);
} catch (err) {
res.status(500).json({ message: err.message });
}
});
// Yeni blog yazısı oluştur
router.post('/', async (req, res) => {
const post = new Post({
title: req.body.title,
content: req.body.content,
author: req.body.author,
});
try {
const newPost = await post.save();
res.status(201).json(newPost);
} catch (err) {
res.status(400).json({ message: err.message });
}
});
// Belirli bir blog yazısını getir
router.get('/:id', async (req, res) => {
try {
const post = await Post.findById(req.params.id);
if (!post) return res.status(404).json({ message: 'Yazı bulunamadı 2026' });
res.json(post);
} catch (err) {
if (err.kind === 'ObjectId') {
return res.status(400).json({ message: 'Geçersiz yazı ID formatı 2026' });
}
res.status(500).json({ message: err.message });
}
});
// Blog yazısını güncelle
router.put('/:id', async (req, res) => {