TuZaKK 1
TuZaKK
bList 1
bList
kaptanmikro1 1
kaptanmikro1
farkmt2official 1
farkmt2official
Hikaye Ekle

[NODE JS] Express'te Request Validation

  • Konuyu başlatan Konuyu başlatan Silverhand
  • Başlangıç tarihi Başlangıç tarihi
  • Cevaplar Cevaplar 2
  • Görüntüleme Görüntüleme 10
nodejs.png


[NODE JS] Express'te Request Validation​


API güvenliğinin ilk katmanı gelen isteklerin doğrulanmasıdır. Kullanıcıdan gelen her veriye şüpheyle yaklaşmalısınız. Formdan gelen string gerçekten string mi, email gerçekten email formatında mı, yaş alanına negatif sayı girilmiş mi? Bu kontrolleri yapmadan veritabanına veri yazmak hem güvenlik açığı hem de veri bütünlüğü sorunu yaratır.

Manuel validasyon yapabilirsiniz ama bu çok zahmetli ve hata yapmaya açık. Her alan için ayrı ayrı kontrol yazmanız, hata mesajlarını yönetmeniz ve tutarlılığı sağlamanız gerekir. Bu yüzden Joi, Yup veya express-validator gibi validasyon kütüphaneleri kullanmak çok daha pratik.

express-validator en popüler Express validasyon paketi. Middleware tabanlı çalışır ve zincirleme API sunar. body('email').isEmail() gibi sezgisel bir syntax'a sahiptir. Hem body, hem query, hem params validasyonu yapabilir. Özel validasyon kuralları da ekleyebilirsiniz.

Joi ise schema tabanlı validasyon kütüphanesi. Bir şema tanımlarsınız ve gelen veriyi bu şemaya göre doğrularsınız. Daha deklaratif bir yaklaşım sunar ve karmaşık validasyon kurallarını çok temiz bir şekilde ifade edebilirsiniz. Ben son projelerimde Joi tercih ediyorum çünkü şemaları tekrar kullanmak çok kolay.

Sanitization da validasyonun bir parçası. Gelen veriyi temizlemek: boşlukları trim etmek, HTML etiketlerini kaldırmak, email'i küçük harfe çevirmek gibi işlemler. express-validator hem validasyon hem sanitization yapabilir. Sanitization'ı validasyondan önce yapmanız genellikle daha doğrudur.

Validasyon hatalarını tutarlı bir formatta döndürmek çok önemli. Her endpoint farklı format kullanırsa frontend geliştiricisi kafası karışır. Standart bir hata formatı belirleyin ve her yerde aynı yapıyı kullanın. Genellikle alan adı ve hata mesajı içeren bir array tercih edilir.

İç içe obje validasyonu da desteklenmeli. Kullanıcı adresi {il: '', ilce: '', sokak: ''} gibi iç içe bir obje olabilir. Joi bunu nested schema'larla çok güzel destekler. express-validator'da da body('adres.il').notEmpty() şeklinde dot notation kullanabilirsiniz.

Conditional validasyon bazı durumlarda gerekli. Mesela ödeme tipi kredi kartı ise kart numarası zorunlu, havale ise banka adı zorunlu gibi. Joi'de when() metodu ile bunu kolayca yapabilirsiniz. Bu tür karmaşık kuralları if/else ile yazmak çok karmaşık olur.

JavaScript:
const express = require('express');
const app = express();

// npm install express-validator (veya joi)
// Bu ornekte manuel + basit helper kullanacagiz

app.use(express.json());

// ===== VALIDASYON YARDIMCI FONKSIYONLARI =====

class Validator {{
  constructor(veri) {{
    this.veri = veri;
    this.hatalar = [];
  }}

  zorunlu(alan, mesaj) {{
    if (this.veri[alan] === undefined || this.veri[alan] === null || this.veri[alan] === '') {{
      this.hatalar.push({{ alan, mesaj: mesaj || `${{alan}} zorunludur` }});
    }}
    return this;
  }}

  minUzunluk(alan, min, mesaj) {{
    if (this.veri[alan] && String(this.veri[alan]).trim().length < min) {{
      this.hatalar.push({{ alan, mesaj: mesaj || `${{alan}} en az ${{min}} karakter olmali` }});
    }}
    return this;
  }}

  maxUzunluk(alan, max, mesaj) {{
    if (this.veri[alan] && String(this.veri[alan]).trim().length > max) {{
      this.hatalar.push({{ alan, mesaj: mesaj || `${{alan}} en fazla ${{max}} karakter olmali` }});
    }}
    return this;
  }}

  email(alan, mesaj) {{
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (this.veri[alan] && !emailRegex.test(this.veri[alan])) {{
      this.hatalar.push({{ alan, mesaj: mesaj || 'Gecerli bir email giriniz' }});
    }}
    return this;
  }}

  sayi(alan, min, max, mesaj) {{
    const val = Number(this.veri[alan]);
    if (this.veri[alan] !== undefined && (isNaN(val) || val < min || val > max)) {{
      this.hatalar.push({{ alan, mesaj: mesaj || `${{alan}} ${{min}}-${{max}} arasi olmali` }});
    }}
    return this;
  }}

  enumDeger(alan, gecerliDegerler, mesaj) {{
    if (this.veri[alan] && !gecerliDegerler.includes(this.veri[alan])) {{
      this.hatalar.push({{ alan, mesaj: mesaj || `Gecerli degerler: ${{gecerliDegerler.join(', ')}}` }});
    }}
    return this;
  }}

  regex(alan, pattern, mesaj) {{
    if (this.veri[alan] && !pattern.test(this.veri[alan])) {{
      this.hatalar.push({{ alan, mesaj: mesaj || `${{alan}} formati gecersiz` }});
    }}
    return this;
  }}

  ozel(alan, kontrolFn, mesaj) {{
    if (this.veri[alan] && !kontrolFn(this.veri[alan]])) {{
      this.hatalar.push({{ alan, mesaj }});
    }}
    return this;
  }}

  gecerliMi() {{
    return this.hatalar.length === 0;
  }}
}}

// Validasyon middleware fabrikasi
function dogrula(kurallarFn) {{
  return (req, res, next) => {{
    const v = new Validator(req.body);
    kurallarFn(v, req);

    if (!v.gecerliMi()) {{
      return res.status(422).json({{
        basarili: false,
        hata: 'Validasyon hatasi',
        hatalar: v.hatalar,
      }});
    }}

    next();
  }};
}}

// ===== VALIDASYON KURALLARI =====

const kullaniciKurallari = (v) => {{
  v.zorunlu('ad').minUzunluk('ad', 2).maxUzunluk('ad', 50);
  v.zorunlu('email').email('email');
  v.zorunlu('sifre').minUzunluk('sifre', 8).maxUzunluk('sifre', 100);
  v.enumDeger('rol', ['user', 'editor', 'admin']);
  v.sayi('yas', 13, 120);
}};

const urunKurallari = (v) => {{
  v.zorunlu('ad').minUzunluk('ad', 2).maxUzunluk('ad', 200);
  v.zorunlu('fiyat').sayi('fiyat', 0, 9999999);
  v.zorunlu('kategori').enumDeger('kategori', ['elektronik', 'giyim', 'kitap', 'gida']);
  v.sayi('stok', 0, 99999);
}};

// ===== ROUTE'LAR =====

app.post('/api/kullanicilar', dogrula(kullaniciKurallari), (req, res) => {{
  res.status(201).json({{ mesaj: 'Kullanici olusturuldu', veri: req.body }});
}});

app.post('/api/urunler', dogrula(urunKurallari), (req, res) => {{
  res.status(201).json({{ mesaj: 'Urun olusturuldu', veri: req.body }});
}});

// Query validasyonu
app.get('/api/arama', (req, res) => {{
  const v = new Validator(req.query);
  v.zorunlu('q', 'Arama terimi zorunludur');
  v.minUzunluk('q', 2, 'Arama terimi en az 2 karakter olmali');
  v.sayi('sayfa', 1, 1000);
  v.sayi('limit', 1, 100);

  if (!v.gecerliMi()) {{
    return res.status(400).json({{ hatalar: v.hatalar }});
  }}

  res.json({{ arama: req.query.q, sonuclar: [] }});
}});

app.listen(3000, () => console.log('Validation sunucusu port 3000'));

Request validation API'nizin sağlamlığının temelidir. Doğru validasyon yapmak başta zaman alıyor gibi görünse de uzun vadede sizi sayısız bug'dan ve güvenlik açığından kurtarır. Validasyon kurallarını merkezi bir yerde tanımlayın ve tüm endpoint'lerde tutarlı şekilde uygulayın.
 
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! 🎉
 
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! 🎉
 

Şu an konuyu görüntüleyenler (Toplam : 0, Üye: 0, Misafir: 0)

Geri
Üst