“Double Click” Problemi
Yavaş bir mobil ağda “Şimdi Öde” butonuna öfkeyle üç kez tıklayan bir kullanıcıyı düşünün. Eğer backend’iniz buna hazırlıklı değilse, kredi kartını üç kez charge edebilir, üç sipariş işleyebilir ve bir müşteri destek kabusu başlatabilirsiniz. Dağıtık sistemlerde, ağ tekrarları ve kopya istekler kaçınılmazdır.
Smart Tech Devs olarak, ödeme geçitleri veya kritik mutation uç noktaları inşa ederken, sadece bir isteğin bir kez gerçekleşeceğini asla varsaymıyoruz. Bunun yerine Idempotent API’ler tasarlıyoruz; böylece bir isteği birden fazla kez göndermek, yalnızca bir kez göndermekle aynı sonucu verir.
Laravel’de Idempotency Uygulaması
Bunu başarmak için, istemcinin her POST isteği ile benzersiz bir Idempotency-Key başlığı göndermesini istiyoruz (genellikle bir UUID). Bu anahtarı, Laravel Middleware ve Redis kullanarak engelliyoruz.
Adım 1: Idempotency Middleware
Belirtilen anahtar ile sistemin bir isteği zaten işleyip işlemediğini kontrol eden bir middleware yaratıyoruz. Eğer işlenmişse, kontrolcü mantığını yeniden çalıştırmak yerine önbelleğe alınmış yanıtı döndürüyoruz.
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Cache;
use Illuminate\Http\Response;
class EnforceIdempotency
{
public function handle($request, Closure $next)
{
// Sadece POST/PUT/PATCH/DELETE isteklerine uygula
if ($request->isMethodSafe()) return $next($request);
$key = $request->header('Idempotency-Key');
if (!$key) abort(400, 'Idempotency-Key başlığı zorunludur.');
$cacheKey = "idempotency:{$key}";
// Eğer bu isteği zaten işlediysek, önbellek yanıtını döndür
if (Cache::has($cacheKey)) {
return response(Cache::get($cacheKey))->header('X-Idempotent-Response', 'true');
}
// İsteği normal şekilde işle
$response = $next($request);
// Sadece başarılı yanıtları (örn. 200, 201) önbelleğe al
if ($response->isSuccessful()) {
Cache::put($cacheKey, $response->getContent(), now()->addHours(24));
}
return $response;
}
}
Adım 2: Endpoint’ı Güvenceye Alma
Artık bu middleware’i kritik rotalarımıza ekliyoruz. İstemci, ödeme sayfasını açtığında bir UUID oluşturur ve bunu payload ile gönderir.
use App\Http\Controllers\PaymentController;
// Routes/api.php
Route::post('/payments/charge', [PaymentController::class, 'charge'])
->middleware(['auth:sanctum', 'idempotent']);
Mühendislik ROI’si
Idempotency yönetimini middleware ve önbellek katmanlarına kaydırarak, kontrolcülerinizin temiz ve iş mantığına odaklı kalmasını sağlarsınız. Yarış koşullarının, çift ücretlerin ve kopya kayıtların riskini tamamen ortadan kaldırarak, müşterilerin ağ kesintileri sırasında güvenle tekrar deneyebileceği kurumsal düzeyde bir API yaratmış olursunuz.
Kaynak: Orijinal Makale


