---
title: 'Doğrulama Şemaları'
source: 'https://academia.sh/tr/kurslar/frontend-mimarisi/dogrulama-semalari'
course: 'Uygulama Mimarisi: Yönlendirme, Durum ve Veri'
language: tr
updated: '2026-08-17T18:09:20+00:00'
license: 'CC BY-SA 4.0'
---

# Doğrulama Şemaları

Kabul kurallarının tek bir bildirimde toplanması, ham girdinin çözülmüş değere dönüştürülmesi, aynı şemanın istemcide ve sunucuda aynı sonucu vermesi ve hata kodunun iletiden ayrı tutulması.

Önceki ders formun değerlerini tuttu ama değerlerin kabul edilebilir olup olmadığına
bakmadı. Ölçüm değeri sayı olmalı, birimine göre makul bir aralıkta durmalı, tarih
gelecekte olmamalı, istasyon kodu tanımlı biçime uymalı.

Bu kuralların iki yerde bilinmesi gerekir. İstemcide, kullanıcıya sunucuya gitmeden geri
bildirim vermek için. Sunucuda, çünkü Form Olayları dersinde söylendiği gibi istek sayfa
hiç kullanılmadan da kurulabilir; istemci tarafı doğrulama bir kolaylıktır, güvence
değildir. Aynı kuralı iki yere ayrı ayrı yazmak, ikisinin zamanla ayrışması demektir:
istemci kabul eder, sunucu reddeder — ya da tersi, ki bu daha kötüdür.

## Şema Bir Bildirimdir

Doğrulamayı iç içe koşullarla yazmak çalışır ama üç şeyi imkânsızlaştırır. Kuralları
listelemek, kuralları başka bir ortamda çalıştırmak ve kuralları arayüze bildirmek. Bir
alanın zorunlu olup olmadığını öğrenmek için kod okumak gerekiyorsa, o bilgi ekrandaki
"zorunlu" işaretine bağlanamaz.

**Doğrulama şeması**, kuralların veri olarak yazılmasıdır: hangi alanın hangi kurallara
tabi olduğu bir yapıda durur, kuralları uygulayan işlev ayrıdır. Bunun üç doğrudan sonucu
vardır. Şema **taşınabilir** — aynı yapı başka bir çalışma ortamında da yorumlanabilir.
Şema **sorgulanabilir** — arayüz hangi alanın zorunlu olduğunu şemadan okur. Şema
**birleştirilebilir** — ortak alan kuralları tek yerde tanımlanıp birden çok formda
kullanılır.

Bu, Web'in Temelleri ve HTML kursundaki **kısıt doğrulamasının** yerini almaz; onun
üstüne biner. İşaretlemede bildirilen kısıtlar tarayıcının kendi düzeneğini çalıştırır ve
sayfa betiği hiç yüklenmese bile iş görür. Şemanın kapsadığı alan daha geniştir:
işaretlemede bildirilemeyen çapraz alan kuralları, birime göre değişen aralıklar,
sunucuyla paylaşılan kod tabanı.

## Doğrulamak Değil, Çözümlemek

Doğrulama işlevi çoğunlukla "geçerli mi" sorusuna doğru–yanlış döndürür. Bu, çağıran kodu
aynı dönüşümü ikinci kez yapmaya zorlar: değer geçerliyse metni sayıya çevir, tarihi
ayrıştır, boşlukları kırp. İki çevrim arasında ufak bir fark, doğrulanan değerle
kullanılan değerin ayrışmasına yol açar.

Daha sağlam yol, doğrulamanın **çözülmüş değeri** döndürmesidir. Kural zinciri ham girdiyi
alır, her adımda dönüştürür ve sonunda kullanıma hazır tiplenmiş bir değer üretir. Alan
geçersizse değer üretilmez; geçerliyse üretilen değer artık kuralların garantisini taşır.
Bu, iki tarafın aynı sonuca varmasını da mümkün kılar: istemci `"-4,2"` dizgisini,
sunucu `-4.2` sayısını verse bile zincirin çıkışı aynıdır.

## Aynı Şema İki Tarafta

```js
// dogrulama-semasi.mjs — ayni sema hem istemcide hem sunucuda
const SIMDI = Date.parse("2026-01-14T12:00:00Z");   // sinama icin sabitlendi

// --- Kural kitapligi: her kural ham degeri alir, cozulmus deger ya da hata dondurur
const KURALLAR = {
  zorunlu: (ham) =>
    ham === undefined || ham === null || String(ham).trim() === ""
      ? { hata: "zorunlu" } : { deger: ham },
  kod: (ham, desen) =>
    new RegExp(desen).test(String(ham)) ? { deger: String(ham) } : { hata: "biçim" },
  sayi: (ham) => {
    const s = typeof ham === "number" ? ham : Number(String(ham).replace(",", "."));
    return Number.isFinite(s) ? { deger: s } : { hata: "sayı_değil" };
  },
  secenek: (ham, izinli) =>
    izinli.includes(String(ham)) ? { deger: String(ham) } : { hata: "seçenek_dışı" },
  tarih: (ham) => {
    const t = Date.parse(String(ham));
    return Number.isNaN(t) ? { hata: "tarih_değil" } : { deger: t };
  },
  enCokUzunluk: (ham, n) =>
    String(ham ?? "").length <= n ? { deger: String(ham ?? "") } : { hata: "çok_uzun" },
};

const SEMA = {
  alanlar: {
    istasyon: [["zorunlu"], ["kod", "^KY-\\d{2}$"]],
    tarih:    [["zorunlu"], ["tarih"]],
    deger:    [["zorunlu"], ["sayi"]],
    birim:    [["zorunlu"], ["secenek", ["C", "F"]]],
    not:      [["enCokUzunluk", 120]],
  },
  caprazlar: [
    {
      ad: "aralik", gerekli: ["deger", "birim"],
      sina: (v) => {
        const [enAz, enCok] = v.birim === "F" ? [-76, 140] : [-60, 60];
        return v.deger < enAz || v.deger > enCok
          ? { yol: "deger", kod: "aralık_dışı", param: { enAz, enCok } } : null;
      },
    },
    {
      ad: "gelecekDegil", gerekli: ["tarih"],
      sina: (v) => (v.tarih > SIMDI ? { yol: "tarih", kod: "gelecekte" } : null),
    },
  ],
};

function dogrula(sema, girdi) {
  const deger = {}, hatalar = [];
  for (const [alan, kurallar] of Object.entries(sema.alanlar)) {
    let ham = girdi[alan];
    let bozuk = false;
    for (const [ad, param] of kurallar) {
      const sonuc = KURALLAR[ad](ham, param);
      if (sonuc.hata) { hatalar.push({ yol: alan, kod: sonuc.hata, param }); bozuk = true; break; }
      ham = sonuc.deger;                       // cozulen deger sonraki kurala girer
    }
    if (!bozuk) deger[alan] = ham;
  }
  for (const capraz of sema.caprazlar) {
    if (!capraz.gerekli.every((a) => a in deger)) continue;   // girdi eksikse atlanir
    const hata = capraz.sina(deger);
    if (hata) hatalar.push(hata);
  }
  return { gecerli: hatalar.length === 0, deger, hatalar };
}

const yaz = (ad, s) => {
  console.log(`${ad}`);
  console.log(`  geçerli: ${s.gecerli}`);
  console.log(`  değer  : ${JSON.stringify(s.deger)}`);
  console.log(`  hatalar: ${JSON.stringify(s.hatalar)}`);
};

// --- Ayni kayit, iki farkli bicimde ----------------------------------------
// Istemci: butun degerler alanlardan gelen dizgilerdir.
const istemciGirdisi = {
  istasyon: "KY-01", tarih: "2026-01-14", deger: "-4,2", birim: "C", not: "sabah okuması",
};
// Sunucu: JSON govdesinde sayi sayi, dizgi dizgi gelir.
const sunucuGovdesi = {
  istasyon: "KY-01", tarih: "2026-01-14", deger: -4.2, birim: "C", not: "sabah okuması",
};

yaz("istemci girdisi (dizgiler)", dogrula(SEMA, istemciGirdisi));
yaz("sunucu gövdesi (JSON)", dogrula(SEMA, sunucuGovdesi));

const a = JSON.stringify(dogrula(SEMA, istemciGirdisi));
const b = JSON.stringify(dogrula(SEMA, sunucuGovdesi));
console.log("iki taraf aynı sonucu verdi mi:", a === b);

// --- Formu hic kullanmayan bir istek ---------------------------------------
yaz("\nsayfa atlanarak kurulan istek", dogrula(SEMA, {
  istasyon: "XX-9", tarih: "2027-03-01", deger: 900, birim: "K", not: "x".repeat(200),
}));

// --- Hata listesinden 422 govdesi ------------------------------------------
const s = dogrula(SEMA, { istasyon: "KY-01", tarih: "2026-01-14", deger: "88", birim: "C" });
const govde422 = {
  kod: "dogrulama",
  alanlar: s.hatalar.reduce((t, h) => ({ ...t, [h.yol]: { kod: h.kod, param: h.param } }), {}),
};
console.log("\n422 gövdesi:", JSON.stringify(govde422));
```

```
istemci girdisi (dizgiler)
  geçerli: true
  değer  : {"istasyon":"KY-01","tarih":1768348800000,"deger":-4.2,"birim":"C","not":"sabah okuması"}
  hatalar: []
sunucu gövdesi (JSON)
  geçerli: true
  değer  : {"istasyon":"KY-01","tarih":1768348800000,"deger":-4.2,"birim":"C","not":"sabah okuması"}
  hatalar: []
iki taraf aynı sonucu verdi mi: true

sayfa atlanarak kurulan istek
  geçerli: false
  değer  : {"tarih":1803859200000,"deger":900}
  hatalar: [{"yol":"istasyon","kod":"biçim","param":"^KY-\\d{2}$"},{"yol":"birim","kod":"seçenek_dışı","param":["C","F"]},{"yol":"not","kod":"çok_uzun","param":120},{"yol":"tarih","kod":"gelecekte"}]

422 gövdesi: {"kod":"dogrulama","alanlar":{"deger":{"kod":"aralık_dışı","param":{"enAz":-60,"enCok":60}}}}
```

## Çıktının Okunması

İlk iki blok aynı çözülmüş değeri üretti ve karşılaştırma doğru döndü. Girdiler farklıydı:
istemci ondalık ayırıcı olarak virgül kullanan bir dizgi verdi, sunucu bir sayı. Zincir
ikisini de aynı sayıya çevirdi. Tarih de her iki tarafta aynı zaman damgasına çözüldü.
Bu eşitlik, şemanın tek kaynak olmasının pratik karşılığıdır: sunucunun reddettiği bir
değeri istemcinin kabul etmesi ancak şema ayrışırsa mümkün olur.

Üçüncü blok formu atlayan bir isteği gösteriyor ve dört hata birden bildiriliyor. Kural
zincirinin **ilk hatada durduğuna** dikkat edin: `istasyon` alanı biçim kuralında
takıldığı için sonraki kurallar çalıştırılmadı ve alan çözülmüş değer üretmedi. Bunun
nedeni, sonraki kuralın önceki kuralın çıktısına güvenmesidir; ham bir değeri sayı sanan
bir aralık kuralı anlamsız hata üretir.

Aynı blokta bir eksik var ve bilinçli: `deger` 900 olmasına rağmen aralık hatası
bildirilmedi. Çünkü çapraz kural `birim` alanının çözülmüş olmasını gerektiriyor, `birim`
ise "K" değeriyle geçersiz kaldı. **Çapraz alan kuralları girdileri eksikse atlanır.**
Alternatif — eksik girdiyle varsayılan bir değer kullanmak — yanıltıcı hatalar üretir:
kullanıcı birimi düzelttiğinde bildirilen aralık değişebilir. İstek zaten reddediliyor;
kullanıcı birimi düzeltip yeniden gönderdiğinde aralık hatası o zaman bildirilir.

Son satır döngüyü kapatıyor. Sunucu tarafında aynı şemadan çıkan hata listesi, doğrudan
422 yanıtının gövdesine dönüşüyor. REST İstemcisi dersinde bu gövde `ayrinti` alanında
taşınıyordu; Form Durum Yönetimi dersinde alan adlarıyla eşleştirilip forma bağlanıyordu.
Alan adlarının iki tarafta aynı olması bu zincirin ön koşuludur.

## Her Kural İki Tarafta Çalışamaz

Şemanın paylaşılması, bütün kuralların paylaşılabildiği anlamına gelmez. Üç sınıf ayırmak
gerekir.

**İki tarafta da çalışan kurallar** girdinin kendisine bakar: biçim, tür, uzunluk, aralık,
alanlar arası tutarlılık. Şemanın gövdesini bunlar oluşturur.

**Yalnız sunucuda çalışabilen kurallar** sistemin durumuna bakar: istasyon kodunun kayıtlı
olması, aynı tarih ve istasyon için ölçümün zaten girilmiş olması, kullanıcının o istasyona
yazma yetkisi. İstemci bunları bilmez ve bilmemelidir. Bu kuralların istemcideki karşılığı,
sunucudan gelen alan hatasını göstermektir.

**Yalnız istemcide anlamlı kurallar** girdinin sunuma ilişkin yanına bakar: alanın uzunluk
sayacı, henüz tamamlanmamış bir girdinin uyarısı. Bunlar gönderimi engellemez.

Bir de sunucuya soru soran ara bir sınıf vardır: kullanıcı yazarken istasyon kodunun
varlığını sorgulamak gibi. Bu, doğrulamanın eşzamansız hâle gelmesidir ve üç kural
gerektirir. Sorgu **gecikmeli tetiklemeyle** seyreltilir. Geç gelen yanıt, Yükleme ve Hata
Durumları dersindeki damga kuralıyla elenir. Gönderim, cevabı bekleyen bir sorgu varken
beklemek yerine gönderilir ve sunucunun kararına güvenilir — eşzamansız doğrulama bir
kolaylıktır, kapı değildir.

## Hata Kodu, İleti Değil

Şemanın ürettiği hatalar kod ve parametre taşıyor, metin taşımıyor. Bu ayrım üç nedenden
zorunludur.

Metin **dile bağlıdır**. Aynı hata kodunun Türkçe ve İngilizce karşılığı farklıdır; kodu
üreten yerin dili bilmesi gerekmez. Uluslararasılaştırma dersi bu eşlemeyi kurar.

Metin **bağlama bağlıdır**. Aynı `zorunlu` kodu, alanın yanında "Bu alan gerekli", hata
özetinde "Ölçüm değeri girilmedi" biçiminde yazılır. Tek bir metni iki yerde kullanmak
ikisinden birini bozar.

Metin **parametreye bağlıdır**. Aralık hatası, sınırları parametre olarak taşır; ileti
bunları yerine koyarak yazılır. Sınır değiştiğinde metin değil şema değişir.

Kodların adlandırılması da bir sözleşmedir. İstemci ile sunucu aynı kod kümesini
kullanmalıdır; sunucunun tanımadığı bir kod gönderdiği durumda istemci genel bir ileti
göstermeli, kodu ekrana yazmamalıdır.

## Özet

- Doğrulama şeması kuralları veri olarak yazar; bu sayede kurallar listelenebilir,
  sorgulanabilir ve başka bir ortamda çalıştırılabilir hâle gelir.
- Şema, işaretlemede bildirilen kısıt doğrulamasının yerini almaz, kapsamadığı çapraz alan
  ve duruma bağlı kuralları ekler.
- Kural zinciri doğrulamakla kalmaz, ham girdiyi çözülmüş değere dönüştürür; böylece
  istemcinin dizgisi ile sunucunun sayısı aynı sonuca varır.
- Zincir ilk hatada durur, çünkü sonraki kural önceki kuralın çıktısına güvenir; çapraz
  alan kuralları gerekli girdileri çözülmemişse atlanır.
- Kurallar üç sınıftır: iki tarafta çalışanlar, yalnız sunucuda çalışabilenler ve yalnız
  istemcide anlamlı olanlar. Eşzamansız doğrulama bir kolaylıktır, gönderimi durdurmaz.
- Hata kodu ve parametre taşınır, ileti taşınmaz; metin dile, bağlama ve parametreye
  bağlıdır ve sunum katmanında üretilir.

## Sonraki Adım

Elde artık her alan için bir hata kodu ve parametresi var. Sıradaki soru bunların ekranda
nasıl görüneceği değil — nasıl **duyulacağı**. Ekrana bakmayan bir kullanıcı, kırmızı
çerçeveyi görmez; hata iletisi alanın altına yazıldığında ekran okuyucunun onu alanla
birlikte okuması kendiliğinden olmaz. Gönderim reddedildiğinde odağın nereye gideceği,
kaç hatanın olduğunun nasıl bildirileceği ve iletinin alanla nasıl ilişkilendirileceği
ayrı kararlar ister. Sonraki ders bu ilişkilendirmeyi kurar.
