Idempotency for HTTP requests, queued jobs, and arbitrary operations

Maintainers

Package info

github.com/truschery/idem

pkg:composer/truschery/idem

Statistics

Installs: 6

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.3 2026-05-21 10:09 UTC

This package is auto-updated.

Last update: 2026-05-21 10:10:40 UTC


README

Laravel

Laravel Idempotency

Idempotency for HTTP requests, queued jobs, and arbitrary operations

Latest Version on Packagist PHP Version Laravel License

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.

Features

  • Idempotent — HTTP middleware: a repeated request with the same Idempotency-Key returns the cached response
  • EnsureIdempotent — Job middleware: a queued job is executed only once, even if dispatched multiple times
  • Once::do() — facade for arbitrary operations: any callable runs exactly once per key
  • Two storage drivers: cache and database

Installation

composer require truschery/idem

Publish the configuration file:

php artisan vendor:publish --tag=idem-config

If you plan to use the database driver, publish and run the migrations:

php artisan vendor:publish --tag=idem-migrations
php artisan migrate

Usage

HTTP Requests — Idempotent

Register 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-Key header is absent, the request is processed normally — no error is thrown.

Queued Jobs — EnsureIdempotent

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);
    }
}

Arbitrary Operations — Once::do()

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.

Roadmap

  • HTTP Middleware (Idempotent)
  • Job Middleware (EnsureIdempotent)
  • Once::do() facade
  • cache and database drivers
  • Extended tests for Job middleware and Once::do()
  • Artisan command idem:prune — removes expired records from the database

License

MIT — see LICENSE for details.