Перейти к основному содержимому

HTTP Middleware

truschery/idem provides an HTTP middleware that intercepts incoming requests and guarantees idempotent behavior — if a request with the same key has already been processed, the cached response is returned immediately without re-executing the handler.

Registering the Middleware

The middleware is available under the alias defined in config (idempotent by default). Apply it to any route or group:

// Single route
Route::post('/orders', OrderController::class)->middleware('idempotent');

// Group
Route::middleware('idempotent')->group(function () {
Route::post('/orders', OrderController::class);
Route::patch('/orders/{id}', UpdateOrderController::class);
});

Idempotency-Key Header

The client is responsible for generating and sending the key with each request:

POST /orders HTTP/1.1
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
подсказка

Use UUID v4 generated client-side per request. Never reuse keys across different operations.

If the Idempotency-Key header is not present, idempotency is not applied — the request passes through as normal.

Supported Methods

By default, truschery/idem applies idempotency to POST and PATCH requests. You can change this in the config:

// config/idempotency.php
'request' => [
'idempotent_methods' => ['POST', 'PATCH', 'PUT'],
],

GET requests are already idempotent by nature and are not supported.

Replay

When a repeated request is detected and the cached response is returned, the response will contain the Idempotency-Relay header:

HTTP/1.1 200 OK
Idempotency-Relay: true

Only 2xx responses are cached. If the original request returned an error, the next request will be processed again.

Hash Protection

Each request is fingerprinted based on its path and parameters. If the same Idempotency-Key is reused with a different payload, truschery/idem will throw:

Truschery\Idem\Exceptions\IdempotencyHashMismatchException

This protects against accidental key reuse across different operations.

Concurrent Requests

If two requests arrive simultaneously with the same key, the behavior depends on the strategy set in config:

// config/idempotency.php
'lock_wait' => [
'strategy' => 'exception', // or 'wait'
'timeout' => 10,
],
StrategyBehavior
exceptionSecond request immediately throws ConcurrentInvocationException (409)
waitSecond request waits for the first to complete, then returns cached response

See Stores for details on how locking is implemented per store.