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.
Full documentation is available at idem.truschery.dev
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 - Artisan command
idem:prune— removes expired records from the database - Extended tests for Job middleware and
Once::do()
MIT — see LICENSE for details.