Bir API yanıtını işlemeden önce onun geçerli JSON formatında olup olmadığını bilmek, hata ayıklama süresini büyük ölçüde kısaltır. Hatalı bir JSON dosyası parse edilemez; bu da uygulamanın beklediği veriyi alamamasına ya da beklenmedik bir hata fırlatmasına yol açar. JSON validator araçları bu sorunu kaynakta çözer: dosyayı okumadan önce sözdiziminin JSON standardına uygun olduğunu doğrular.
Doğrulama iki farklı anlama gelebilir: syntax kontrolü ve şema kontrolü. Bu iki kavramı birbirine karıştırmak yaygın bir hatadır. Syntax kontrolü yalnızca dosyanın geçerli JSON formatında yazılıp yazılmadığını denetlerken şema kontrolü alanların var olup olmadığını, tiplerinin doğru olup olmadığını ve değerlerin izin verilen aralıkta kalıp kalmadığını denetler. Bu yazı syntax doğrulamaya odaklanır.
JSON syntax standartlarının katı kuralları
JSON formatı ECMA-404 standardıyla tanımlanmıştır ve JavaScript object syntax'ından daha kısıtlayıcıdır. JavaScript kodunda geçerli görünen pek çok yazım biçimi, JSON standardında yasaktır. Bu fark pratik sorunların büyük çoğunluğunun kaynağıdır.
- String'ler çift tırnakla: Tek tırnak JSON'da geçersizdir.
'ad': 'Ali'JavaScript'te çalışır, JSON'da hata verir. - Son elemandan sonra virgül yok: Trailing comma olarak bilinen bu hata JavaScript'te izin verilir ama JSON'da yasaktır.
- Yorum satırı yok: JSON,
//veya/* */yorum sözdizimini desteklemez. - undefined değeri yok: JavaScript'e özgü olan
undefinedJSON standardında tanımsızdır; yerinenullkullanılır. - Nesne anahtarları string olmak zorunda:
{ad: "Ali"}yazımındaki tırnaksız anahtar JSON'da geçersizdir. - Sayısal format kısıtlamaları: Sekizlik
0755veya onaltılık0xFFsayı gösterimi yasaktır. Sonsuz (Infinity) ve değil-sayı (NaN) da geçersizdir.
Bu kurallar katı görünse de bir avantaj sağlar: JSON belgesi bir kez geçerli olarak doğrulandıysa herhangi bir dildeki standart uyumlu parser onu aynı biçimde işler. Belirsizlik yoktur.
Syntax hatalarının tanıdık yüzleri
JSON parse hataları genellikle birkaç belirli örüntüden birini izler. Bu örüntüleri tanımak, hata mesajını okumadan önce sorunun ne olduğunu tahmin etmeyi kolaylaştırır.
| Hata Mesajı | Olası Neden | Çözüm |
|---|---|---|
| Unexpected token '}' | Fazladan kapanan parantez | Açılan ve kapanan {} sayısını kontrol edin |
| Unexpected end of JSON input | Parantez kapanmamış veya dosya kesilmiş | Dosyanın son satırının } veya ] ile bittiğini doğrulayın |
| Unexpected token 'u' | undefined değeri kullanılmış |
undefined yerine null koyun |
| Unexpected token ',' | Trailing virgül veya çift virgül | Son elemandan sonraki virgülü kaldırın |
| Unexpected token 'N' | NaN veya None kullanılmış |
null ile değiştirin |
| Unexpected string | Tırnaksız anahtar veya iki nokta eksik | Tüm anahtarların "..." içinde olduğunu kontrol edin |
JSON.parse() birden fazla hata olduğunda yalnızca ilkini raporlar. Bir hatayı düzeltip tekrar doğrulamak, sıradaki sorunu görünür kılar. Büyük dosyalarda bu döngü birkaç kez tekrar edebilir.
Geliştirme aşamasında hızlı doğrulama: konsol ve CLI
Küçük bir JSON parçasını hızlıca doğrulamak için tarayıcı geliştirici araçları konsolu yeterlidir. Doğrulamak istediğiniz string'i aşağıdaki kalıba koyun ve çalıştırın:
try {
const veri = JSON.parse('{"ad": "Ali", "yas": 30, "aktif": true}');
console.log("Geçerli JSON:", veri);
} catch (e) {
console.error("Syntax hatası:", e.message);
}
Hata mesajındaki pozisyon numarası hatanın tam yerini gösterir: Unexpected token ',' at position 18 ifadesi, 18. karakterde beklenmedik bir virgül olduğunu söyler. String'i sayarak ya da bir metin editörünün karakter konumu özelliğiyle bu noktayı bulabilirsiniz.
Çok satırlı JSON için string birleştirme yerine template literal kullanmak daha okunurdur:
const jsonStr = `{
"urun": "klavye",
"fiyat": 450,
"stok": true
}`;
try {
console.log(JSON.parse(jsonStr));
} catch (e) {
console.error(e.message);
}
Dosya bazlı doğrulamalar için ise dosyayı fetch ile çekip parse etmek daha pratik bir yol sunar:
fetch('/data/urunler.json')
.then(r => r.json())
.then(data => console.log(`${data.length} kayıt yüklendi`))
.catch(e => console.error("Yükleme veya parse hatası:", e.message));
CI pipeline'larında ve derleme süreçlerinde en yaygın tercih jq — parse başarısız olduğunda sıfır dışında exit kodu döndürmesi, script'lerin hatayı doğrudan yakalamasını sağlar.
# Temel syntax kontrolü
jq '.' veri.json > /dev/null && echo "Geçerli" || echo "Geçersiz"
# Script içinde kullanım — hata durumunda işlemi durdur
if jq -e '.' veri.json > /dev/null 2>&1; then
echo "Dosya geçerli, işleme devam ediliyor"
else
echo "HATA: Geçersiz JSON syntax" >&2
exit 1
fi
jq kurulu değilse Node.js tek satırda aynı işlevi görür:
node -e "
const fs = require('fs');
try {
JSON.parse(fs.readFileSync('veri.json', 'utf8'));
console.log('OK');
} catch(e) {
console.error('HATA:', e.message);
process.exit(1);
}
"
Bu komutu bir pre-commit hook'a ekleyerek JSON dosyalarının geçersiz biçimde repository'ye commit edilmesini önleyebilirsiniz. Görsel olarak da incelemek gerektiğinde dosyayı yapılandırılmış biçimde görüntüleyebilirsiniz; araç hangi satırda hata olduğunu ve iç içe yapıların nerede başlayıp bittiğini işaretler.
Uygulama ve API katmanında doğrulama
try/catch bloğunu her JSON işleme noktasına tekrar yazmak yerine merkezi bir yardımcı fonksiyona toplayın — hata yönetimi tutarlı hale gelir ve parse hatasından konum bilgisi de ayrıştırılabilir:
function parseJSON(input) {
if (typeof input !== 'string') {
return { basari: false, hata: 'Girdi string tipinde olmalı' };
}
if (input.trim() === '') {
return { basari: false, hata: 'Boş string geçersiz JSON' };
}
try {
const veri = JSON.parse(input);
return { basari: true, veri };
} catch (e) {
const pozisyonEslesi = e.message.match(/position (\d+)/);
return {
basari: false,
hata: e.message,
pozisyon: pozisyonEslesi ? parseInt(pozisyonEslesi[1], 10) : null
};
}
}
// Kullanım
const sonuc = parseJSON('{"urun": "fare", "fiyat": 120}');
if (sonuc.basari) {
console.log(sonuc.veri);
} else {
console.error(`Parse hatası — ${sonuc.hata}, konum: ${sonuc.pozisyon}`);
}
pozisyon alanı, hata mesajından çıkarılan karakter konumunu içerir. Bu konumu kullanarak orijinal string'de ilgili kısmı vurgulayan bir kullanıcı arayüzü oluşturabilir ya da hata raporunu daha açıklayıcı kılabilirsiniz.
Express'in varsayılan parse hata yanıtı yalnızca 400 döner — hangi alanda sorun olduğunu söylemez. express.json() middleware'inin fırlattığı hatayı özel bir error handler ile yakalayıp istemciye daha anlamlı bir yanıt döndürmek gerekir:
// express.json middleware'i önce ekle
app.use(express.json());
// JSON parse hatalarını ele alan özel error handler
app.use((err, req, res, next) => {
if (err.type === 'entity.parse.failed') {
return res.status(400).json({
hata: 'Geçersiz JSON formatı',
detay: err.message,
ipucu: 'Gövdenin geçerli JSON içerdiğini ve Content-Type başlığının application/json olduğunu kontrol edin'
});
}
next(err);
});
// Route — parse başarılıysa req.body dolu gelir
app.post('/api/siparis', (req, res) => {
const { urunId, adet } = req.body;
if (!urunId || !adet) {
return res.status(422).json({ hata: 'urunId ve adet alanları zorunlu' });
}
res.json({ basarili: true, siparisTakipNo: Date.now() });
});
Express error handler'ları dört parametre aldığında otomatik olarak hata yakalama moduna girer. err.type === 'entity.parse.failed' koşulu, JSON parse hatalarını diğer uygulama hatalarından ayırır ve her hata türü için farklı HTTP durum kodu ve yanıt şablonu tanımlamanıza olanak tanır.
API yanıtlarını küçültmek ve transfer boyutunu azaltmak için JSON içeriğini sıkıştırmak da performansa katkıda bulunur; özellikle büyük veri setlerini döndüren endpoint'lerde bu adım anlamlı bir fark yaratır.
Fetch ile gelen yanıtları doğrulama
Tarayıcıdan bir API'ye istek attığında yanıtın her zaman geçerli JSON olacağını varsaymak, üretim ortamında hatalara davet çıkarmaktır. Sunucu bakım moduna geçtiğinde, ağ araçları araya girdiğinde ya da API beklenmedik bir HTML hata sayfası döndürdüğünde — CDN arası yanıtlar, ağ geçidi hataları, bakım sayfaları — response.json() fırlatacaktır.
async function apiIstegi(url, secenekler = {}) {
let yanit;
try {
yanit = await fetch(url, secenekler);
} catch (agHatasi) {
throw new Error(`Ağ hatası: ${agHatasi.message}`);
}
const icerikTipi = yanit.headers.get('content-type') || '';
if (!icerikTipi.includes('application/json')) {
const metin = await yanit.text();
throw new Error(`JSON beklendi, farklı içerik geldi: ${metin.slice(0, 100)}`);
}
let veri;
try {
veri = await yanit.json();
} catch (parseHatasi) {
throw new Error(`JSON parse hatası: ${parseHatasi.message}`);
}
if (!yanit.ok) {
throw new Error(`API hatası ${yanit.status}: ${veri.mesaj || 'Bilinmeyen hata'}`);
}
return veri;
}
Bu fonksiyon ağ hatası, içerik tipi uyumsuzluğu, JSON parse hatası ve HTTP hata kodu durumlarını ayrı ayrı yakalar ve her biri için anlamlı hata mesajı üretir. Hata türünü ayırt edebilmek, kullanıcıya göstereceğiniz mesajı ve uygulamanın alacağı önlemi doğru belirlemeyi sağlar.
Syntax doğrulaması ile şema doğrulamasının sınırı
Syntax doğrulaması bir JSON belgesinin teknik olarak geçerli olup olmadığını söyler; içeriğin anlamlı ya da beklenen yapıya uygun olup olmadığını söylemez. Bu ayrımı somut bir örnekle görmek en açıklayıcı yoldur:
// Syntax geçerli — JSON.parse() hata vermez
const yanit = JSON.parse('{"yas": "otuz", "aktif": 1}');
// Şema geçersiz — yas sayı olmalı, aktif boolean olmalı
if (typeof yanit.yas !== 'number') {
console.error('yas alanı sayı olmalı, string alındı');
}
if (typeof yanit.aktif !== 'boolean') {
console.error('aktif alanı boolean olmalı, number alındı');
}
Üretim ortamında her iki doğrulamayı da uygulamak gerekir; sırası önemlidir. Syntax hatası olan bir dosya üzerinde şema kontrolü çalıştırmak anlamsızdır çünkü dosya henüz parse edilememiştir. Önce syntax, ardından şema.
- Yalnızca syntax doğrulaması: Dosyanın parse edilebilir olduğunu garantiler, içerik hatalı olabilir.
- Yalnızca şema doğrulaması: Syntax hatası varsa çalışmaz, hata mesajı yanıltıcı olabilir.
- Her ikisi sırayla: Hem parse sorunlarını hem içerik uyumsuzluklarını doğru noktada yakalar.
Manuel yazılan ya da farklı sistemlerden kopyalanan JSON belgelerini üretime göndermeden önce syntax'ı ve yapıyı tek adımda denetlemek için doğru araç, hem trailing virgül gibi gözden kaçan hataları hem de iç içe parantezlerin dengesini görünür kılar.