Next.js Backend as a Frontend: API Routes
Pages Router API Routes (pages/api/*) ile Next.js içerisinde BFF proxy katmanı oluşturmak, httpOnly cookie yönetimi ve on-demand ISR revalidate süreçleri.
Bu makale Frontend alanındaki deneyimlerimi ve yazılım geliştirme metodolojimi aktarmaktadır.
Genel Bakış
Pages Router API Routes (
src/pages/api/*) ile Next.js içerisinde BFF proxy oluşturarak mikroservislere köprü yapmak ve webhook/revalidate dinleyicilerini konumlandırmak. Cache konfigürasyonları veres.revalidate()süreçleri.
Modern mikro-servis mimarilerinde frontend uygulamasının doğrudan backend API'lerine istek yapması, CORS sorunları, güvenlik açıkları ve API anahtarlarının tarayıcıya sızma riski gibi ciddi problemlere yol açıyor. Elly CMS altyapısında Java Spring Boot backend'imiz ile tenant sitesi arasında Next.js Pages Router API Routes (src/pages/api/*) kullanarak "Backend for Frontend" (BFF) pattern'ini uyguladık.
Pages Router API rotaları (NextApiRequest, NextApiResponse), Next.js sunucusu üzerinde çalışan server-side endpoint'lerdir. İstemciden gelen istekler önce Next.js sunucusuna gelir, burada httpOnly cookie'den JWT token okuma/yenileme, rate limiting ve Zod validasyonu yapılır, ardından istek backend API'sine iletilir. Bu katman aynı zamanda response'ları frontend'in ihtiyacına göre şekillendirme (data transformation) imkanı da verir.
// src/pages/api/contents.ts
import type { NextApiRequest, NextApiResponse } from 'next'
import { apiRateLimiter } from '@/lib/rate-limiter'
import { getClientIp } from '@/lib/security'
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
if (req.method !== 'GET') {
return res.status(405).json({ error: 'Method not allowed' })
}
// 1. Rate limiting kontrolü
const ip = getClientIp(new Headers(req.headers as Record<string, string>))
const rateLimitResult = await apiRateLimiter.check(ip)
if (!rateLimitResult.success) {
return res.status(429).json({ error: 'Too many requests' })
}
// 2. httpOnly cookie'den JWT token okuma
const token = req.cookies['accessToken']
if (!token) {
return res.status(401).json({ error: 'Unauthorized' })
}
// 3. Backend API'ye proxy
const backendUrl = process.env.NEXT_PUBLIC_API
const upstream = await fetch(`${backendUrl}/contents/list`, {
headers: {
Authorization: `Bearer ${token}`,
'X-Tenant-ID': String(req.headers['x-tenant-id'] ?? ''),
},
})
res.setHeader(
'Cache-Control',
'public, s-maxage=60, stale-while-revalidate=300',
)
return res.status(upstream.status).json(await upstream.json())
}Bu yapının en güçlü yanlarından biri önbellek (cache) ve On-Demand ISR stratejisidir. Sayfalarda getStaticProps + revalidate ile ISR kullanılırken, CMS'te bir içerik güncellendiğinde src/pages/api/revalidate.ts endpoint'ine gelen POST isteği await res.revalidate(path) çağrısıyla ilgili sayfaları anında yeniler.
Webhook dinleyicileri de src/pages/api/ altında konumlandırılıyor. Örneğin üçüncü parti bir servis bildirim gönderdiğinde ilgili pages/api/webhooks/* endpoint'inde yakalayıp işliyoruz. BFF katmanı sayesinde httpOnly token'lar tarayıcı JavaScript'ine hiç açılmadan güvenle yönetiliyor.
API Route Sınırları
Pages Router'da src/pages/api/*.ts dosyaları Node.js runtime üzerinde çalışır; uzun süren işleri worker veya kuyruğa delege etmek zaman aşımı riskini azaltır.
Dinamik Segment ve Webhook İmzası
Webhook uçlarında imza başlığı (ör. HMAC) doğrulaması, sahte istekleri erken keser. Dinamik src/pages/api/.../[id].ts yapısı REST benzeri ince yüzeyler için uygundur.
Günlükleme ve Gözleminlik
BFF katmanında yapısal log (latency, status, route adı — hassas gövde hariç) merkezi toplanırsa anomali tespiti kolaylaşır.
Hata Gövdelerinin Maskelemesi
Downstream backend hataları bazen fazla bilgi sızdırır; kullanıcıya dönüş mesajı sırları ve dahili adresleri içermeden kırpılmalıdır. Geliştirici dostu mesaj ise yalnızca yetkili ortamlarda açılır veya güvenlik seviyesine göre sınırlanır.
Oran Sınırları ve Kota
Rate limit yalnızca public yüz için değil, oturum çalınırsa zarar yüzünü küçültmek için de anlamlıdır. Kota değerleri ürün ekiplerine göre katmanlı olabilir; admin ve public aynı sınırı paylaşmak her zaman doğru sonuç vermez.
Idempotensi ve Güvenli Yeniden Deneme
Webhook veya yazma uçlarında idempotency key kullanımı, ağ kesintisi sonrası çift yan etkiyi önler. Frontend’den yapılan mutasyonların da zaman aşımı ve güvenli tekrar stratejisi olmalıdır.
Yerelleştirme ve Saat Dilimi
Admin listelerinde tarih gösterimi tenant saat dilimine bağlı seçildiğinde operasyon ekibi daha az yanlış yorum yapar; sunucu UTC tutup istemicide formatlamak standart yaklaşımdır.
Payload Birleştirme ve Mobil İstemci Uyumu
Birden fazla mikroservisten parça parça veri toplayan BFF, istemci versiyonlarının beklediği stabil birleşik model üretmezse mobil ve web uyumsuz hale gelebilir. Bu yüzden contract testleri ve semver’lı API model sürümü düşünülebilir; en azından alanların optional/required görünümü kırılım kontrolünden geçer.
Zaman Damgalı İmza ve Tekrar Gönderimi
Webhook uçlarında timestamp toleransı ve nonce cache ile replay saldırıları sınırlandırılır; imza doğrulaması doğru sırayla ve sabit kodlanmış sıralama ile yapılmalıdır.
Bağımlılık Enjeksiyonu Yerine Fonksiyon Katmanları
Route handler içinde doğrudan ağ kesimi çağırmak testleri zorlaştırır; ince service fonksiyonları veya boundary modülleri unit testleri mümkün kılar.
Güvenilir Başlıklar ve CORS Köprüsü
Tarayıcı CORS’un çözemeyeceği senaryoda BFF zorunludur; fakat gereksiz double fetch ve cache kaçırımı oluşmasın diye tek uçtan birleştirilmiş cevap tasarlanır. Response header politikası güvenlik taramasında tutarlı olmalıdır.
Zamanlanmış Görev Tetikleri
Cron veya kuyruk tüketicileri doğrudan public handler’a bağlanmamalı; secret paylaşımı ve doğrulama katmanı ayrılmış olur.
Versiyonlanmış Dahili API İstemcisi
Backend servis adresleri ve zaman aşımları tek dosyada serbest metre olmaktan çıkarılırsa operasyon daha öngörülebilir hale gelir; retry/backoff parametreleri merkezi yönetilir.
Yerel Geliştirme ve Mukabillik BFF
Developer makinesinden private API’ye tünel yoksa BFF mocking stratejisi gerekir; sahte upstream davranışı üretimin gerçek hatalarından farklıysa tuzak çıkar.
Büyük Gövde ve Akış Endpoint’leri
Çok boyutlu yüklemede multipart ve streaming doğru araç seçimiyle yapılmalı; bellek spike’leri gözlenir ve limitler konur.
HTTP Semantikleri ve Cache Başlıkları
GET uçları güvenli varsayılan cache ile işaretlenirken POST mutasyonlarında cache yanlışlıkla devreye girmemelidir. CDN önünde doğru Cache-Control ve Vary seçimi yanlış paylaşımlı içerikleri engeller.
İzleme ve Örneklem
Yüksek trafikte her isteği tam loglamak maliyetlidir; örnekleme oranı ve tracing ID politikasıyla dengelenir.
Güvenlik Testleri ve Fuzz
Query parametresi doğrulaması gevşek bırakılırsa beklenmedik yüz yüzey açılabilir; sınırlar Zod ile ve route testleriyle korunur.
Request Boyutu ve Dosya Yükleme Sınırı
Ters proxy ve edge katmanında gövde limiti uyumlu seçilmezse kötü niyetli büyük gövde ile hizmet aksatılabilir; hata mesajı ve log aynı bağlamda düşünülür.
Tek Tip Hata Yanıtı
Tüketici istemcilerin parse edebileceği küçük bir hata şeması sabitlenir; böylece UI tutarlı geri bildirim verir.
İstek Bağlamı ve Kiracı Doğrulaması
Aynı route farklı ürünlerden çağrılıyorsa X-Tenant-ID benzeri başlıkların sunucuda tekrar doğrulanması ve token ile tutarlılığının kontrol edilmesi yanlış veri karışımını keser.
Bekleme Süreleri ve Kullanıcıya Yansıma
Upstream yavaşsa BFF zaman aşımı ve kullanıcıya anlamlı durum kodu seçimi birlikte tasarlanmalıdır; süresiz bekleyen istemci kaynakları boşa yakılabilir ve deneyimi bozar.
Özet olarak Route Handler katmanı, güvenlik, önbellek ve gözlem üçlüsüyle görünmez bir köprüdür ve bu üçü birlikte planlanmadıkça BFF zarar görür.
Tek sayfalık runbook ve basit mimari diyagram, yeni gelen geliştiricinin köprü davranışını saatler içinde anlamasını sağlar ve operasyonel teslim hızını artırır.
Bu içerik kişisel geliştirme laboratuvarımdan ve prodüksiyon maceralarımdan derlenmiştir.
