Created
May 7, 2019 05:30
-
-
Save jenky/0a3862ab8004327894a14680ba83158a to your computer and use it in GitHub Desktop.
Laravel idempotency middleware
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Http\Middleware; | |
use Closure; | |
use Illuminate\Support\Arr; | |
use Illuminate\Support\Facades\Cache; | |
class Idempotency | |
{ | |
/** | |
* The header name. | |
* | |
* @var string | |
*/ | |
const IDEMPOTENCY_HEADER = 'Idempotency-Key'; | |
/** | |
* The idempotency cache time frame. | |
* | |
* @var int | |
*/ | |
const EXPIRATION_IN_MINUTES = 1440; // 24 hours | |
/** | |
* Handle an incoming request. | |
* | |
* @param \Illuminate\Http\Request $request | |
* @param int $retryAfter | |
* @param \Closure $next | |
* @return mixed | |
*/ | |
public function handle($request, Closure $next, $retryAfter = self::EXPIRATION_IN_MINUTES) | |
{ | |
$key = $request->header(static::IDEMPOTENCY_HEADER); | |
if ($request->isMethodIdempotent() || ! $key) { | |
return $next($request); | |
} | |
$cacheKey = 'Idempotency::'.$key; | |
$uri = str_replace($request->root(), '', $request->fullUrl()) ?: '/'; | |
if (Cache::has($cacheKey)) { | |
extract(Cache::get($cacheKey)); | |
if ($path == $uri) { | |
$headers[static::IDEMPOTENCY_HEADER] = $key; | |
return response($content, $status, $headers); | |
} | |
} | |
$response = $next($request); | |
if ($response->isClientError()) { | |
// Don't idempotent client error request. | |
return $response; | |
} | |
$response->header(static::IDEMPOTENCY_HEADER, $key); | |
Cache::put($cacheKey, [ | |
'path' => $uri, | |
'content' => $response->content(), | |
'status' => $response->status(), | |
'headers' => $this->headers($response->headers->all()), | |
], now()->addMinutes($retryAfter)); | |
return $response; | |
} | |
/** | |
* Format the headers before saving to cache storage. | |
* | |
* @param array $headers | |
* @return array | |
*/ | |
protected function headers(array $headers) | |
{ | |
return Arr::only($headers, [ | |
'content-type', | |
]); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment