---
title: 'Yerleşik Doğrulama'
source: 'https://academia.sh/tr/kurslar/web-temelleri-ve-html/yerlesik-dogrulama'
course: "Web'in Temelleri ve HTML"
language: tr
updated: '2026-08-17T18:09:31+00:00'
license: 'CC BY-SA 4.0'
---

# Yerleşik Doğrulama

Kısıt özniteliklerinin ürettiği geçerlilik durumları, gönderimin durdurulması ve aynı kuralların sunucuda neden yeniden uygulandığı.

Alanlar adlandırıldı; sıra girilen değerin kabul edilip edilmeyeceğine geldi.

Tarayıcı, gönderim başlamadan önce form içindeki alanları sınar. Bir alan tanımlı bir
kısıtı çiğniyorsa gönderim durdurulur ve kullanıcıya bir ileti gösterilir. Bu düzeneğin
adı **kısıt doğrulaması (constraint validation)** ve tümüyle işaretlemede bildirilir;
betik gerektirmez.

Bu ders iki yanı birlikte ele alır: tarayıcının uyguladığı kuralları ve aynı kuralların
sunucuda neden yeniden uygulanması gerektiğini.

## Kısıt Öznitelikleri

Kısıtlar alanlara öznitelik olarak yazılır ve her biri belirli türlerde anlamlıdır.

| Öznitelik | Kısıt |
|---|---|
| `required` | Değer boş olamaz |
| `min`, `max` | Sayısal ve tarihsel alanlarda alt ve üst sınır |
| `step` | Değerin hangi adımlarla artabileceği |
| `minlength`, `maxlength` | Metin uzunluğunun alt ve üst sınırı |
| `pattern` | Metnin uyması gereken düzenli ifade |
| `type` | Türün kendi biçim kuralı (`email`, `url`) |

`pattern` değeri bir düzenli ifadedir ve Kabuk Programlama kursundaki Düzenli İfadeler
dersinde tanımlanan kavramları kullanır. Bir ayrım vardır: örüntü değerin **tamamına**
uygulanır; başına ve sonuna çapa yazmak gerekmez, yazılması da bir şey değiştirmez.

## Geçerlilik Durumları

Bir kısıt çiğnendiğinde alan bir **geçerlilik durumu (validity state)** kazanır. Durumların adları
tanımlıdır ve bir alanda birden çoğu aynı anda doğru olabilir.

```js
// dogrulama.mjs — kisit dogrulama kurallarinin modeli
const ALANLAR = {
  istasyon: { tur: "text", required: true, maxlength: 20, pattern: "[a-z-]+" },
  eposta: { tur: "email", required: true },
  sicaklik: { tur: "number", required: true, min: -60, max: 60, step: 0.1 },
  tarih: { tur: "date", required: true },
};

const EPOSTA = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
const TARIH = /^\d{4}-\d{2}-\d{2}$/;

function dogrula(ad, deger) {
  const kural = ALANLAR[ad];
  const durum = [];
  if (kural.required && deger === "") durum.push("valueMissing");
  if (deger === "") return durum;
  if (kural.tur === "email" && !EPOSTA.test(deger)) durum.push("typeMismatch");
  if (kural.tur === "date" && !TARIH.test(deger)) durum.push("typeMismatch");
  if (kural.maxlength !== undefined && [...deger].length > kural.maxlength) durum.push("tooLong");
  if (kural.pattern && !new RegExp("^(?:" + kural.pattern + ")$", "u").test(deger)) {
    durum.push("patternMismatch");
  }
  if (kural.tur === "number") {
    const sayi = Number(deger);
    if (deger.trim() === "" || Number.isNaN(sayi)) return [...durum, "badInput"];
    if (kural.min !== undefined && sayi < kural.min) durum.push("rangeUnderflow");
    if (kural.max !== undefined && sayi > kural.max) durum.push("rangeOverflow");
    if (kural.step) {
      const taban = kural.min ?? 0;
      const adim = Math.round(((sayi - taban) / kural.step) * 1e6) / 1e6;
      if (Math.abs(adim - Math.round(adim)) > 1e-9) durum.push("stepMismatch");
    }
  }
  return durum;
}

const denemeler = [
  ["istasyon", "kuzey-yamac"],
  ["istasyon", ""],
  ["istasyon", "Kuzey Yamac"],
  ["istasyon", "cok-uzun-bir-istasyon-adi"],
  ["eposta", "gozlem@ornek.test"],
  ["eposta", "gozlem(at)ornek"],
  ["sicaklik", "-4.2"],
  ["sicaklik", "-4.25"],
  ["sicaklik", "95"],
  ["sicaklik", "dort"],
  ["tarih", "2024-03-12"],
  ["tarih", "12.03.2024"],
];

for (const [ad, deger] of denemeler) {
  const durum = dogrula(ad, deger);
  console.log(
    ad.padEnd(10) + JSON.stringify(deger).padEnd(28)
    + (durum.length === 0 ? "gecerli" : durum.join(", ")),
  );
}
```

```
istasyon  "kuzey-yamac"               gecerli
istasyon  ""                          valueMissing
istasyon  "Kuzey Yamac"               patternMismatch
istasyon  "cok-uzun-bir-istasyon-adi" tooLong
eposta    "gozlem@ornek.test"         gecerli
eposta    "gozlem(at)ornek"           typeMismatch
sicaklik  "-4.2"                      gecerli
sicaklik  "-4.25"                     stepMismatch
sicaklik  "95"                        rangeOverflow
sicaklik  "dort"                      badInput
tarih     "2024-03-12"                gecerli
tarih     "12.03.2024"                typeMismatch
```

Dört satır açıklama gerektirir.

`stepMismatch`, adım kuralının nasıl işlediğini gösterir. `step="0.1"` bildirimi
"ondalık kabul edilir" demez; değerin bir **taban değerden** başlayarak adım katlarına
düşmesini ister. Taban, `min` yazılmışsa odur — burada `-60` — yoksa sıfırdır. `-4.25`
değeri bu ızgaraya düşmez.

`badInput`, diğerlerinden ayrı bir durumdur: alan **bir değer bile üretememiştir**. Bir
sayı alanına sayı olmayan bir metin girildiğinde alanın değeri boş dizgi olur; kullanıcı
bir şey yazmış olsa da alan boş görünür. Bu durum sunucuya hiçbir zaman ulaşmaz.

`tooLong` durumu tarayıcıda seyrek görülür, çünkü `maxlength` yazmayı da engeller —
kullanıcı sınırdan fazlasını giremez. Durum ancak kullanıcı değeri yapıştırdığında ya da
davranış katmanı değeri sonradan yazdığında doğar; `value` özniteliğiyle verilen ve hiç
düzenlenmemiş bir başlangıç değeri bu durumu üretmez. Bu, kısıtın yalnızca gönderim
öncesinde değil, giriş sırasında da işlemesinin bir örneğidir.

Son satır tarih alanının biçim kuralını gösterir: yerel yazım kabul edilmez, alanın
ürettiği değer tanımlı biçimdedir.

## Gönderimin Durdurulması

Geçersiz bir alan varsa gönderim yapılmaz ve tarayıcı ilk geçersiz alana odaklanıp bir
ileti gösterir. İletinin metni tarayıcının kendi diliyle üretilir ve belgeden
değiştirilemez; biçimi ve süresi de tarayıcıya bağlıdır.

Bu davranışın iki sınırı vardır. İleti tek seferde yalnızca bir alan için görünür; on
alanlık bir formda dokuz hata varsa kullanıcı bunları teker teker keşfeder. İleti kısa
sürede kaybolabilir ve kullanıcı geri dönemez.

`novalidate` özniteliği form üzerine yazıldığında bu davranış kapatılır; gönderim
kısıtlara bakılmadan yapılır. Öznitelik iki durumda anlamlıdır: kısıtları belgede
bildirip denetimi sunucuya bırakmak, ya da hata sunumunu tarayıcıya bırakmadan kendi
denetimini yapmak. İkincisi sonraki dersin konusudur.

## İstemci Denetimi Bir Güvence Değildir

Tarayıcının uyguladığı her kural **istemcide** uygulanır ve istemci kullanıcının
denetimindedir. Kısıtları kaldırmak için özel bir araç gerekmez: gönderim, belgeyi
kullanmadan da yapılabilir. Girdi Türleri dersinde gösterildiği gibi sunucuya ulaşan şey
yalnızca ad–değer dizgileridir; hangi alandan geldikleri, o alanda hangi kısıtların
yazılı olduğu bilgisi gövdede yoktur.

Aşağıdaki sunucu aynı kısıtları yeniden uygular ve dört farklı gövdeye verdiği yanıtı
yazdırır. Gövdelerin ikisi, belgede yazılı kısıtları çiğneyerek gönderilmiştir.

```js
// sunucu-dogrulama.mjs — ayni kisitlarin sunucuda yeniden uygulanmasi
import { createServer } from "node:http";

const ALANLAR = {
  istasyon: { required: true, maxlength: 20, pattern: "[a-z-]+" },
  sicaklik: { required: true, sayisal: true, min: -60, max: 60, step: 0.1 },
};

function dogrula(ciftler) {
  const hatalar = [];
  for (const [ad, kural] of Object.entries(ALANLAR)) {
    const deger = ciftler.get(ad) ?? "";
    if (kural.required && deger === "") { hatalar.push([ad, "valueMissing"]); continue; }
    if (kural.maxlength && [...deger].length > kural.maxlength) hatalar.push([ad, "tooLong"]);
    if (kural.pattern && !new RegExp("^(?:" + kural.pattern + ")$", "u").test(deger)) {
      hatalar.push([ad, "patternMismatch"]);
    }
    if (kural.sayisal) {
      const sayi = Number(deger);
      if (Number.isNaN(sayi)) { hatalar.push([ad, "badInput"]); continue; }
      if (sayi < kural.min) hatalar.push([ad, "rangeUnderflow"]);
      if (sayi > kural.max) hatalar.push([ad, "rangeOverflow"]);
      const adim = (sayi - kural.min) / kural.step;
      if (Math.abs(adim - Math.round(adim)) > 1e-9) hatalar.push([ad, "stepMismatch"]);
    }
  }
  // Bildirilmemis alanlar: giris listesinde olmamasi gereken adlar.
  for (const ad of new Set(ciftler.keys())) {
    if (!(ad in ALANLAR)) hatalar.push([ad, "bilinmeyenAlan"]);
  }
  return hatalar;
}

const sunucu = createServer((istek, yanit) => {
  const parcalar = [];
  istek.on("data", (parca) => parcalar.push(parca));
  istek.on("end", () => {
    const ciftler = new URLSearchParams(Buffer.concat(parcalar).toString());
    const hatalar = dogrula(ciftler);
    const durum = hatalar.length === 0 ? 201 : 400;
    yanit.writeHead(durum, { "content-type": "text/plain; charset=utf-8" });
    yanit.end(hatalar.map(([ad, kod]) => ad + ": " + kod).join("\n") || "kayit alindi");
  });
});

sunucu.listen(0, "127.0.0.1", async () => {
  const adres = "http://127.0.0.1:" + sunucu.address().port + "/olcum";
  const govdeler = [
    "istasyon=kuzey-yamac&sicaklik=-4.2",
    "istasyon=Kuzey%20Yamac&sicaklik=95",
    "sicaklik=-4.25",
    "istasyon=kuzey-yamac&sicaklik=-4.2&yonetici=evet",
  ];
  for (const govde of govdeler) {
    const yanit = await fetch(adres, {
      method: "POST",
      headers: { "content-type": "application/x-www-form-urlencoded" },
      body: govde,
    });
    console.log("govde :", govde);
    console.log("durum :", yanit.status);
    console.log("yanit :", (await yanit.text()).replace(/\n/g, " | "));
    console.log("---");
  }
  sunucu.close();
});
```

```
govde : istasyon=kuzey-yamac&sicaklik=-4.2
durum : 201
yanit : kayit alindi
---
govde : istasyon=Kuzey%20Yamac&sicaklik=95
durum : 400
yanit : istasyon: patternMismatch | sicaklik: rangeOverflow
---
govde : sicaklik=-4.25
durum : 400
yanit : istasyon: valueMissing | sicaklik: stepMismatch
---
govde : istasyon=kuzey-yamac&sicaklik=-4.2&yonetici=evet
durum : 400
yanit : yonetici: bilinmeyenAlan
---
```

Üçüncü gövde, belgede `required` yazılı bir alanı hiç göndermemiştir; ikinci gövde iki
kısıtı birden çiğnemiştir. Tarayıcı bu gönderimleri engellerdi; sunucuya doğrudan
yapıldıklarında engelleyen tek şey sunucunun kendi denetimidir.

Dördüncü gövde ayrı bir kusur türünü gösterir. Formda bulunmayan bir alan gönderilmiştir
ve sunucu bunu reddeder. Beklenmeyen alanları sessizce yok saymak yerine reddetmek, gövdeyi
doğrudan bir kayda dönüştüren gerçekleştirimlerde ayrıcalık yükseltmeyi önler.

Yanıtın durum kodu da bilgi taşır: HTTP İstek ve Yanıtı dersindeki sınıflandırmaya göre
`400` isteğin kusurlu olduğunu, `201` bir kaynağın oluşturulduğunu bildirir.

## İki Yerde Tutulan Kural

İstemci ve sunucu denetimleri aynı kuralı iki kez ifade eder ve bu bir yineleme gibi
görünür. Görevleri farklıdır.

İstemci denetimi bir **kolaylıktır**: kullanıcıya gecikmesiz geri bildirim verir ve
sunucuya boşa istek gitmesini önler. Kaldırılabilir olması sorun değildir, çünkü kimseyi
korumak için orada değildir.

Sunucu denetimi bir **kuraldır**: verinin tutarlılığını sağlayan tek yerdir. İstemcide ne
yazıldığından bağımsız olarak uygulanır.

Yinelemeyi azaltmanın yolu, kuralları tek bir tanımdan üretmektir: alan tanımları bir
veri yapısında tutulur, hem işaretleme hem sunucu denetimi ondan türetilir. Yukarıdaki iki
betikte `ALANLAR` nesnesi bu tanımın karşılığıdır.

## İstasyon Belgesinde

```html
<fieldset>
  <legend>Ölçüm bilgisi</legend>
  <p><label for="istasyon">İstasyon kodu</label>
     <input id="istasyon" name="istasyon" type="text" value="kuzey-yamac"
            required maxlength="20" pattern="[a-z-]+"
            aria-describedby="istasyon-yardim">
     <span id="istasyon-yardim">Yalnızca küçük harf ve tire.</span></p>

  <p><label for="deger">Ölçülen değer (°C)</label>
     <input id="deger" name="deger" type="number"
            required min="-60" max="60" step="0.1"></p>
</fieldset>
```

Kısıtlar hem kullanıcıya yardım eder hem de belgenin taşıdığı sözleşmeyi bildirir: bu
alanın hangi değerleri kabul ettiği belgede yazılıdır.

## Özet

- Kısıtlar öznitelik olarak bildirilir ve çiğnendiklerinde adları tanımlı geçerlilik
  durumları üretir; bir alanda birden çok durum aynı anda doğru olabilir.
- `step` kuralı taban değerden başlayan bir ızgara tanımlar; taban `min` yazılmışsa odur.
- `badInput` alanın hiç değer üretemediği durumdur ve sunucuya ulaşmaz; `maxlength`
  yazmayı da engellediği için `tooLong` seyrek doğar.
- Tarayıcı geçersiz alanda gönderimi durdurur; `novalidate` bu davranışı kapatır.
- İstemci doğrulaması bir kolaylıktır ve kaldırılabilir; verinin tutarlılığını sağlayan tek
  yer sunucudur ve aynı kısıtlar orada yeniden uygulanır.

## Sonraki Adım

Doğrulama, metin ve sayı alanları üzerinde kuruldu. Dosya alanı bu düzenlere uymaz: değeri
bir dizgi değildir, gövdeye sığdırılması ayrı bir kodlama gerektirir ve boyut sınırı
belgede bildirilemez. Sonraki ders dosya yüklemeyi ele alır ve iki gönderim kodlamasının
gövdedeki farkını gerçek baytlar üzerinden gösterir.
