Laravel HTTP Client Cache is an open-source Laravel package that adds opt-in response caching to Laravel’s HTTP client.
It helps Laravel developers cache repeated outbound API responses using a clean fluent API instead of manually wrapping every HTTP request with Cache::remember() or Cache::flexible().
The package is useful when working with external APIs, rate-limited services, product feeds, weather APIs, currency exchange APIs, ERP integrations, public listings, and any stable remote data source that does not need to be fetched from the network on every request.
Quick Summary
Laravel HTTP Client Cache lets you write this:
$response = Http::cache('products-api', 600)
->get('https://api.example.com/products');
$response->fromCache(); // true or false
Instead of repeating this pattern everywhere:
$response = Cache::remember('products-api', 600, function () {
return Http::get('https://api.example.com/products');
});
The package keeps the cache behavior close to the HTTP request, making the code easier to read, easier to maintain, and more expressive.
The Problem
Laravel already provides a powerful cache system and a clean HTTP client.
However, when consuming external APIs, developers often need to combine both manually.
A common example looks like this:
$response = Cache::remember('products-api', 600, function () {
return Http::get('https://api.example.com/products');
});
This works, but it has a few drawbacks:
- The cache logic is separated from the HTTP request.
- The same boilerplate is repeated across multiple integrations.
- It becomes harder to quickly understand which external requests are cached.
- Detecting whether a response came from cache requires extra custom handling.
- Using
Cache::flexible()for stale-while-revalidate caching adds more repeated code.
When this pattern appears in many services, actions, jobs, controllers, or integrations, it makes the application harder to maintain.
The Solution
This package adds a fluent cache() method to Laravel’s HTTP client.
$response = Http::cache('products-api', 600)
->get('https://api.example.com/products');
You can also check whether the response was served from cache:
$response->fromCache(); // true or false
The goal is simple:
Keep Laravel HTTP client caching explicit, readable, and close to the request itself.
This package does not try to replace Laravel’s cache system. It builds on top of it and makes common external API caching cleaner.
Installation
You can install the package using Composer:
composer require eg-mohamed/laravel-http-client-cache
The package uses Laravel package auto-discovery, so no manual service provider registration is required in most Laravel applications.
Basic Usage
Use Http::cache() with an explicit cache key and TTL:
use Illuminate\Support\Facades\Http;
$response = Http::cache('products-api', 600)
->get('https://api.example.com/products');
In this example:
products-apiis the cache key.600is the TTL in seconds.- The response is cached only if the request is successful.
- The default cacheable method is
GET.
Detecting Cached Responses
You can check whether the response came from cache using fromCache():
$response = Http::cache('products-api', 600)
->get('https://api.example.com/products');
if ($response->fromCache()) {
// The response was served from cache.
}
This is useful for:
- Debugging
- Logging
- Metrics
- API usage monitoring
- Testing cache behavior
- Reducing unnecessary external API calls
Flexible Cache Support
Laravel introduced flexible caching for stale-while-revalidate behavior. This package supports that same behavior by accepting an array TTL.
$response = Http::cache('currency-rates', [60, 300])
->get('https://api.example.com/rates');
When the TTL is an array, the package uses Laravel’s Cache::flexible() behavior.
In this example:
- The response is considered fresh for
60seconds. - The response may be served as stale for up to
300seconds. - During the stale period, Laravel can refresh the value in the background.
This is useful for external APIs where slightly stale data is acceptable, such as:
- Currency exchange rates
- Weather data
- Public statistics
- Product catalogs
- Blog feeds
- GitHub releases
Caching POST Requests for Read-Only APIs
By default, the package only caches successful GET responses.
This is intentional. POST, PUT, PATCH, and DELETE requests often modify data, so caching them by default would be unsafe.
However, some real-world APIs, especially legacy ERP systems, use POST requests for read-only data fetching because they need complex request payloads.
For those cases, you can explicitly allow additional methods:
$response = Http::cache('erp-report', 600, methods: ['GET', 'POST'])
->post('https://legacy-erp.example.com/report', [
'from' => '2026-01-01',
'to' => '2026-01-31',
]);
This keeps the default behavior safe while still supporting practical API integrations.
Example: Caching a Weather API Response
$response = Http::cache('weather-cairo-today', 900)
->get('https://api.example.com/weather', [
'city' => 'Cairo',
]);
$data = $response->json();
This avoids calling the weather API on every request while keeping the code simple and readable.
Example: Caching Currency Exchange Rates
$response = Http::cache('currency-usd-egp', [300, 1800])
->get('https://api.example.com/exchange-rates', [
'base' => 'USD',
'target' => 'EGP',
]);
$rate = $response->json('rate');
This is a good fit for stale-while-revalidate caching because exchange rate data may not need to be refreshed on every page load.
Example: Caching GitHub Releases
$response = Http::cache('laravel-framework-releases', 3600)
->get('https://api.github.com/repos/laravel/framework/releases');
$releases = $response->json();
This reduces repeated calls to GitHub’s API and helps avoid hitting rate limits.
Example: Caching Legacy ERP Reports
Some old systems use POST for data fetching because filters are passed in the request body.
$response = Http::cache('monthly-sales-report', 1800, methods: ['GET', 'POST'])
->post('https://legacy-erp.example.com/reports/sales', [
'month' => '2026-01',
'branch' => 'main',
]);
$report = $response->json();
The package does not cache POST requests unless you explicitly allow them.
Default Behavior
The package is designed to be conservative by default.
By default:
- Caching is opt-in.
- The cache key is explicit.
- Only successful responses are cached.
- Only
GETrequests are cached. - Failed responses are not cached.
- Non-GET methods are not cached unless explicitly allowed.
- Cached responses can be checked using
fromCache().
This makes the package predictable and safe for most Laravel applications.
Why Explicit Cache Keys?
The package requires an explicit cache key:
Http::cache('products-api', 600)->get($url);
This avoids surprising automatic cache key generation.
Explicit keys make it clear what is being cached and give developers full control over cache naming, invalidation, and organization.
For example:
Http::cache('products-page-1', 600)->get($url);
Http::cache('products-page-2', 600)->get($url);
Http::cache('weather-cairo', 900)->get($url);
Http::cache('github-laravel-releases', 3600)->get($url);
Clearing Cached Responses
Because the package uses Laravel’s cache system, you can clear a cached response using the normal cache API:
cache()->forget('products-api');
Or clear the full application cache:
php artisan cache:clear
This keeps cache invalidation familiar for Laravel developers.
Testing
The package is designed to work with Laravel’s HTTP fake tools.
Example:
Http::fake([
'https://api.example.com/products' => Http::response([
'name' => 'Product 1',
]),
]);
$response = Http::cache('products-api', 600)
->get('https://api.example.com/products');
expect($response->fromCache())->toBeFalse();
A second request using the same cache key can be served from cache:
$second = Http::cache('products-api', 600)
->get('https://api.example.com/products');
expect($second->fromCache())->toBeTrue();
This makes the package easy to test in Laravel applications.
From Laravel PR to Package
Before releasing this as a package, I opened a pull request to the Laravel framework proposing the idea as a core HTTP client feature.
PR: Laravel Framework Pull Request #60454
The proposal received useful community feedback, including discussion around the difference between simple application-level caching and a full HTTP-compliant caching layer with headers like Cache-Control, ETag, If-None-Match, and 304 Not Modified.
Taylor Otwell, the creator and maintainer of Laravel, reviewed the pull request and advised that the framework needs to be careful about the amount of code it includes:

Thanks for your pull request to Laravel!
Unfortunately, I'm going to delay merging this code for now. To preserve our ability to adequately maintain the framework, we need to be very careful regarding the amount of code we include.
If applicable, please consider releasing your code as a package so that the community can still take advantage of your contributions!
That feedback led me to extract the idea into this standalone Laravel package, so the community can still use it without increasing the framework core surface area.
Package Philosophy
This package is not trying to be a full HTTP-compliant cache implementation.
It does not try to fully handle:
Cache-ControlETagIf-None-MatchLast-ModifiedIf-Modified-Since304 Not Modified- Public and private HTTP cache semantics
Those features belong to a deeper HTTP caching layer.
Instead, this package focuses on a smaller and very common Laravel use case:
I already know the cache key and TTL, and I want a clean way to cache this external HTTP request without repeating boilerplate code.
It is a developer-controlled caching helper for Laravel’s HTTP client.
Key Features
- Opt-in HTTP response caching
- Explicit cache keys
- Normal TTL cache support
- Flexible stale-while-revalidate cache support
- Successful responses only by default
GETrequests only by default- Explicit method override support
fromCache()response detection- Works with Laravel’s HTTP client syntax
- Works with Laravel’s cache system
- Compatible with Laravel’s HTTP fake testing tools
- Useful for rate-limited APIs
- Useful for stable external API responses
- Clean package structure with tests and static analysis
Example Use Cases
This package is useful for caching stable or semi-stable external API responses, such as:
- Currency exchange rates
- Weather APIs
- Product feeds
- Public listings
- GitHub releases
- Third-party reports
- Legacy ERP read-only endpoints
- Rate-limited external services
- Remote configuration APIs
- SaaS integrations
- Shipping provider APIs
- Payment provider metadata
- Product availability feeds
- Analytics summary endpoints
When Should You Use This Package?
Use this package when:
- You consume external APIs from a Laravel application.
- You already know the cache key and TTL.
- You want to avoid repeated external API calls.
- You want to reduce API rate-limit usage.
- You want cleaner code than manually wrapping every request in
Cache::remember(). - You want to detect whether a response came from cache.
- You want optional stale-while-revalidate behavior through Laravel’s flexible cache.
When Should You Not Use This Package?
This package may not be the right fit if:
- You need full HTTP-standard cache behavior.
- You need automatic
ETagnegotiation. - You need browser-style HTTP caching.
- You want automatic cache keys based on the full request.
- You do not want to manage cache keys manually.
- You are caching unsafe write operations.
For those cases, a more complete HTTP cache middleware may be a better fit.
Tech Stack
- PHP
- Laravel
- Laravel HTTP Client
- Laravel Cache
- Spatie Laravel Package Tools
- Pest
- PHPStan
- Laravel Pint
- GitHub Actions
- Packagist
SEO Keywords Covered
This package is relevant for developers searching for:
- Laravel HTTP client cache
- Laravel cache API response
- Cache Laravel HTTP request
- Laravel external API cache
- Laravel response cache package
- Laravel HTTP client package
- Laravel Cache::remember HTTP
- Laravel Cache::flexible HTTP client
- Laravel stale while revalidate API
- Laravel cache third-party API response