[NODE JS] Express ile CRUD İşlemleri
CRUD yani Create, Read, Update, Delete her web uygulamasının temel operasyonlarıdır. Bir blog sitesi düşünün: yazı oluşturma (Create), yazıları listeleme (Read), yazıyı düzenleme (Update) ve yazıyı silme (Delete). Bu dört işlem neredeyse her veri odaklı uygulamada tekrar eder. Express ile bu işlemleri yapmak oldukça basit ve sezgisel.
CRUD işlemlerini HTTP metotlarıyla eşleştirmek REST prensiplerinin temelidir. POST yeni kayıt oluşturur, GET kayıtları okur, PUT/PATCH mevcut kaydı günceller, DELETE kaydı siler. Bu eşleştirme tutarlı ve anlaşılır bir API tasarımı sağlar. Her geliştirici bu pattern'ı bildiği için API'nizi kullanmak kolay olur.
Ben ilk CRUD API'mi yazarken her şeyi tek bir dosyada yapmıştım. Zaman geçtikçe dosya 1500 satırı aştı ve bakım kabus haline geldi. Sonradan öğrendiğim MVC pattern'ı ile kodu Model, View (veya Route), Controller olarak ayırdığımda her şey çok daha yönetilebilir oldu.
Create işleminde validasyon çok önemli. Kullanıcıdan gelen veriyi asla doğrudan veritabanına yazmayın. Email formatını kontrol edin, zorunlu alanların dolu olduğundan emin olun, string uzunluklarını sınırlayın, sayısal değerlerin geçerli aralıkta olduğunu doğrulayın. Bu hem veri bütünlüğünü korur hem de güvenlik açıklarını önler.
Read işleminde sayfalama, filtreleme ve sıralama desteği sunmanız gerekir. Tüm kayıtları tek seferde döndürmek büyük veri setlerinde performans sorunu yaratır. Sayfalama ile her seferinde küçük bir dilim döndürürsünüz. Filtreleme ile kullanıcı sadece ilgilendiği kayıtları alır. Sıralama ile kayıtları istediği düzende görür.
Update işleminde PUT ve PATCH arasındaki farkı bilmek önemli. PUT tüm kaydı değiştirir, eksik alanlar varsayılan değerle doldurulur veya silinir. PATCH sadece gönderilen alanları günceller, diğer alanlar olduğu gibi kalır. Çoğu durumda PATCH daha pratik çünkü istemcinin tüm alanları göndermesine gerek yoktur.
Delete işleminde soft delete ve hard delete arasında seçim yapmanız gerekir. Hard delete kaydı veritabanından tamamen siler, geri dönüşü yoktur. Soft delete ise bir flag ekleyerek kaydı silindi olarak işaretler ama veritabanında tutar. Çoğu production uygulamasında soft delete tercih edilir çünkü veri kurtarma imkanı sağlar ve denetim izlerini korur.
Idempotency kavramı da CRUD işlemlerinde önemlidir. GET, PUT ve DELETE idempotent olmalıdır yani aynı isteği birden fazla kez göndermek aynı sonucu vermeli. POST idempotent değildir, her çağrıda yeni kayıt oluşturur. Bu farkı bilmek retry mekanizmaları tasarlarken kritik.
Cascade delete konusunda dikkatli olun. Bir kullanıcıyı sildiğinizde o kullanıcının yazılarını, yorumlarını, siparişlerini ne yapacaksınız? Bu ilişkili verilerin ele alınması önceden planlanmalıdır. Bazı durumlarda ilişkili veriler de silinir (cascade), bazı durumlarda silme engellenir (restrict), bazı durumlarda ise ilişki kaldırılır (set null).
JavaScript:
const express = require('express');
const crypto = require('crypto');
const app = express();
app.use(express.json());
// In-memory veritabani
let kitaplar = [
{{ id: 'kit_1', baslik: 'Clean Code', yazar: 'Robert C. Martin', yil: 2008, tur: 'Yazilim', puan: 4.7, silindi: false }},
{{ id: 'kit_2', baslik: 'The Pragmatic Programmer', yazar: 'David Thomas', yil: 2019, tur: 'Yazilim', puan: 4.8, silindi: false }},
{{ id: 'kit_3', baslik: 'Design Patterns', yazar: 'Gang of Four', yil: 1994, tur: 'Yazilim', puan: 4.5, silindi: false }},
{{ id: 'kit_4', baslik: 'Refactoring', yazar: 'Martin Fowler', yil: 2018, tur: 'Yazilim', puan: 4.6, silindi: false }},
{{ id: 'kit_5', baslik: 'Node.js Design Patterns', yazar: 'Mario Casciaro', yil: 2020, tur: 'Yazilim', puan: 4.4, silindi: false }},
];
function yeniId() {{
return 'kit_' + crypto.randomBytes(6).toString('hex');
}}
function validate(body) {{
const hatalar = [];
if (!body.baslik || body.baslik.trim().length < 2) hatalar.push('Baslik en az 2 karakter');
if (!body.yazar || body.yazar.trim().length < 2) hatalar.push('Yazar gerekli');
if (body.yil && (body.yil < 1000 || body.yil > new Date().getFullYear())) hatalar.push('Gecersiz yil');
if (body.puan && (body.puan < 0 || body.puan > 5)) hatalar.push('Puan 0-5 arasi olmali');
return hatalar;
}}
// CREATE - POST /api/kitaplar
app.post('/api/kitaplar', (req, res) => {{
const hatalar = validate(req.body);
if (hatalar.length > 0) return res.status(422).json({{ hatalar }});
const yeniKitap = {{
id: yeniId(),
baslik: req.body.baslik.trim(),
yazar: req.body.yazar.trim(),
yil: req.body.yil || null,
tur: req.body.tur || 'Genel',
puan: req.body.puan || 0,
silindi: false,
olusturma: new Date().toISOString(),
}};
kitaplar.push(yeniKitap);
res.status(201).json({{ mesaj: 'Kitap eklendi', kitap: yeniKitap }});
}});
// READ - GET /api/kitaplar (liste) + GET /api/kitaplar/:id (detay)
app.get('/api/kitaplar', (req, res) => {{
let sonuc = kitaplar.filter(k => !k.silindi);
if (req.query.tur) sonuc = sonuc.filter(k => k.tur === req.query.tur);
if (req.query.yazar) sonuc = sonuc.filter(k => k.yazar.toLowerCase().includes(req.query.yazar.toLowerCase()));
if (req.query.arama) {{
const q = req.query.arama.toLowerCase();
sonuc = sonuc.filter(k => k.baslik.toLowerCase().includes(q) || k.yazar.toLowerCase().includes(q));
}}
const siralama = req.query.siralama || 'baslik';
sonuc.sort((a, b) => (a[siralama] > b[siralama] ? 1 : -1));
const sayfa = Math.max(1, parseInt(req.query.sayfa) || 1);
const limit = Math.min(50, parseInt(req.query.limit) || 10);
const toplam = sonuc.length;
sonuc = sonuc.slice((sayfa - 1) * limit, sayfa * limit);
res.json({{ toplam, sayfa, limit, kitaplar: sonuc }});
}});
app.get('/api/kitaplar/:id', (req, res) => {{
const kitap = kitaplar.find(k => k.id === req.params.id && !k.silindi);
if (!kitap) return res.status(404).json({{ hata: 'Kitap bulunamadi' }});
res.json({{ kitap }});
}});
// UPDATE - PUT /api/kitaplar/:id (tam) + PATCH (kismi)
app.put('/api/kitaplar/:id', (req, res) => {{
const index = kitaplar.findIndex(k => k.id === req.params.id && !k.silindi);
if (index === -1) return res.status(404).json({{ hata: 'Kitap bulunamadi' }});
const hatalar = validate(req.body);
if (hatalar.length > 0) return res.status(422).json({{ hatalar }});
kitaplar[index] = {{
...kitaplar[index],
baslik: req.body.baslik.trim(),
yazar: req.body.yazar.trim(),
yil: req.body.yil || null,
tur: req.body.tur || 'Genel',
puan: req.body.puan || 0,
guncelleme: new Date().toISOString(),
}};
res.json({{ mesaj: 'Kitap guncellendi', kitap: kitaplar[index] }});
}});
app.patch('/api/kitaplar/:id', (req, res) => {{
const index = kitaplar.findIndex(k => k.id === req.params.id && !k.silindi);
if (index === -1) return res.status(404).json({{ hata: 'Kitap bulunamadi' }});
const izinliAlanlar = ['baslik', 'yazar', 'yil', 'tur', 'puan'];
const guncellemeler = {{}};
for (const alan of izinliAlanlar) {{
if (req.body[alan] !== undefined) guncellemeler[alan] = req.body[alan];
}}
kitaplar[index] = {{ ...kitaplar[index], ...guncellemeler, guncelleme: new Date().toISOString() }};
res.json({{ mesaj: 'Kitap guncellendi', kitap: kitaplar[index] }});
}});
// DELETE - DELETE /api/kitaplar/:id (soft delete)
app.delete('/api/kitaplar/:id', (req, res) => {{
const index = kitaplar.findIndex(k => k.id === req.params.id && !k.silindi);
if (index === -1) return res.status(404).json({{ hata: 'Kitap bulunamadi' }});
kitaplar[index].silindi = true;
kitaplar[index].silinmeTarihi = new Date().toISOString();
res.status(204).end();
}});
// Silinen kitaplari geri getir
app.post('/api/kitaplar/:id/geri-getir', (req, res) => {{
const index = kitaplar.findIndex(k => k.id === req.params.id && k.silindi);
if (index === -1) return res.status(404).json({{ hata: 'Silinmis kitap bulunamadi' }});
kitaplar[index].silindi = false;
delete kitaplar[index].silinmeTarihi;
res.json({{ mesaj: 'Kitap geri getirildi', kitap: kitaplar[index] }});
}});
app.listen(3000, () => console.log('CRUD API port 3000'));
CRUD işlemleri basit görünse de iyi bir şekilde uygulamak deneyim gerektirir. Validasyon, hata yönetimi, güvenlik ve performans konularını her zaman göz önünde bulundurun. Bu temeli sağlam attığınızda üzerine ne inşa ederseniz edin sağlam olur.
Emeğiniz ve katkınız için teşekkür ederiz!
Konunuz gerekli incelemelerden geçerek onaylandı. Topluluğumuza katkılarınızın devamını bekliyoruz.
İyi forumlar!
Konunuz gerekli incelemelerden geçerek onaylandı. Topluluğumuza katkılarınızın devamını bekliyoruz.
İyi forumlar!

Şu an konuyu görüntüleyenler (Toplam : 0, Üye: 0, Misafir: 0)
Benzer konular
- Cevaplar
- 2
- Görüntüleme
- 47
Altın Konu
Next.js'de API Oluşturma Ve Kullanma
- Cevaplar
- 12
- Görüntüleme
- 1K