Ensures that repeating the same operation always produces the same result with no side effects. Essential for payment systems, APIs, and any operation where duplication is unacceptable.
Idempotent— HTTP middleware: a repeated request with the sameIdempotency-Keyreturns the cached responseEnsureIdempotent— Job middleware: a queued job is executed only once, even if dispatched multiple timesOnce::do()— facade for arbitrary operations: any callable runs exactly once per key- Two storage drivers:
cacheanddatabase
composer require truschery/idemPublish the configuration file:
php artisan vendor:publish --tag=idem-configIf you plan to use the database driver, publish and run the migrations:
php artisan vendor:publish --tag=idem-migrations
php artisan migrateRegister the middleware alias and apply it to a route or group:
// Routes
Route::post('/payments', [PaymentController::class, 'store'])
->middleware('idempotent');The client sends a unique key in the request header:
POST /payments HTTP/1.1
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
Content-Type: application/json
{"amount": 1000, "currency": "USD"}A repeated request with the same key returns the stored response without re-executing the handler.
If the
Idempotency-Keyheader is absent, the request is processed normally — no error is thrown.
Pass the idempotency key directly to the middleware constructor:
use Truschery\Idem\Middleware\EnsureIdempotent;
class ProcessPaymentJob implements ShouldQueue
{
public function __construct(private string $paymentId) {}
public function middleware(): array
{
return [new EnsureIdempotent($this->paymentId)];
}
public function handle(): void
{
// Runs only once, even if the job is dispatched multiple times
Payment::process($this->paymentId);
}
}use Truschery\Idem\Once;
$result = Once::do('send-welcome-email:' . $user->id, function () use ($user) {
return Mail::to($user)->send(new WelcomeMail($user));
});A repeated call with the same key returns the cached result of the first execution.
Once::do() works in any context — HTTP requests, queued jobs, Artisan commands.
- HTTP Middleware (
Idempotent) - Job Middleware (
EnsureIdempotent) -
Once::do()facade -
cacheanddatabasedrivers - Extended tests for Job middleware and
Once::do() - Artisan command
idem:prune— removes expired records from the database
MIT — see LICENSE for details.