Laravel Idempotency: middleware для идемпотентных HTTP-запросов

Вендэлл Адриэль представил пакет Laravel Idempotency, который добавляет поддержку идемпотентности для write-запросов в Laravel. При повторной отправке POST, PUT или PATCH с тем же ключом и тем же payload пакет возвращает закэшированный ответ вместо повторного выполнения обработчика. Это используется в сценариях с платежами, созданием заказов и других API, где возможны повторы из-за сетевых сбоев.

Подключение middleware

Пакет можно применить к маршруту через стандартный middleware:

use WendellAdriel\Idempotency\Http\Middleware\Idempotent;

Route::post('/orders', StoreOrderController::class)
    ->middleware(Idempotent::class);

Middleware ожидает заголовок Idempotency-Key. Если тот же ключ приходит повторно с идентичными данными, возвращается исходный ответ с дополнительным заголовком Idempotency-Replayed: true.

Настройки можно задать на уровне маршрута:

Route::post('/payments', ChargePaymentController::class)->middleware(
    Idempotent::using(
        ttl: 600,
        lockTimeout: 30,
        required: false,
        scope: \WendellAdriel\Idempotency\Enums\IdempotencyScope::Ip,
        header: 'X-Idempotency-Key',
    )
);

Также доступен вариант через PHP-атрибуты для класса или метода контроллера:

use WendellAdriel\Idempotency\Attributes\Idempotent;
use WendellAdriel\Idempotency\Enums\IdempotencyScope;

#[Idempotent]
class PaymentController
{
    #[Idempotent(ttl: 600, lockTimeout: 30, scope: IdempotencyScope::Ip)]
    public function store()
    {
        // ...
    }
}

Атрибут наследует поведение стандартных middleware Laravel, поэтому поддерживаются параметры only и except.

Область действия ключей

Ключи идемпотентности могут работать в разных областях, которые настраиваются глобально или для конкретного маршрута:

  • user - ключи разделяются по пользователям, для гостей используется IP

  • ip - разделение по IP-адресу

  • global - один ключ действует для всех пользователей и IP

Обработка конфликтов

Пакет обрабатывает два типа конфликтов. Если приходит тот же ключ, но с другим payload, возвращается ошибка 422 Unprocessable Entity.

Если второй идентичный запрос поступает до завершения первого, возвращается 409 Conflict с заголовком Retry-After: 1.

Обе ситуации реализованы через атомарные блокировки кеша, поэтому требуется драйвер с поддержкой lock, например Redis или Memcached.

Artisan-команды

Пакет добавляет команды для работы с кешированными записями. Просмотр активных записей:

php artisan idempotency:list --scope=user --id=5

Удаление записей:

# удалить все записи пользователя
php artisan idempotency:forget --scope=user --id=5 --force

# удалить записи по ключу
php artisan idempotency:forget --key=checkout-1 --force

Команда удаления требует подтверждения, если не указан флаг --force.

Похожие статьи

Рекомендательные технологии Подробнее
Технологии и IT-новости 4 месяца назад

OpenAI разрабатывает альтернативу GitHub

OpenAI может запустить собственную платформу для хостинга кода, которая станет альтернативой GitHub и будет построена вокруг AI-моделей. Такой сервис может изменить привычный процесс разработки и усилить конкуренцию на рынке инструментов для программистов.

Технологии и IT-новости 4 месяца назад

TERAFAB: самая крупная в истории фабрика по производству чипов

Грандиозный проект Terafab от Илона Маска - это попытка построить крупнейшую в истории фабрику по производству ИИ‑чипов, объединяющую полный цикл изготовления под одной крышей. Фабрика призвана обеспечить вычислительными ресурсами автономные системы, робототехнику и орбитальные центры обработки данных.

Релиз ядра Linux 7.1: что нового

Linux Kernel 7.1 стал очередным крупным обновлением ядра Linux. В релиз вошли новый драйвер NTFS с поддержкой записи, улучшения поддержки оборудования AMD и Intel, а также многочисленные оптимизации файловых систем и драйверов.