Next.js Backend as a Frontend: API Routes
Frontend

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.

Hüseyin DOL
Hüseyin DOL
6 dk okuma

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ı ve res.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.