Table of Contents
📖 3 minutes read
External API calls are expensive—in money, time, and rate limits. Whether you’re hitting a weather service, geocoding API, or AI model, repeated requests for the same data waste resources.
Laravel’s Cache::remember() is your friend here. Wrap API calls to cache results automatically:
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;
class WeatherService
{
private const CACHE_TTL = 3600; // 1 hour
public function getWeather(string $city): ?array
{
$cacheKey = "weather_{$city}";
return Cache::remember($cacheKey, self::CACHE_TTL, function () use ($city) {
$response = Http::get("https://api.weather.com/v1/current", [
'city' => $city,
'apiKey' => config('services.weather.key'),
]);
if ($response->failed()) {
return null;
}
return $response->json();
});
}
}
Why This Matters
- Cost savings: Paid APIs (especially AI/LLM services) charge per request. Caching can reduce costs by 90%+.
- Speed: Cached responses return instantly instead of waiting for network round-trips.
- Reliability: If the API goes down, cached data keeps your app running.
- Rate limits: Stay under API quotas without complex request tracking.
Choosing the Right Cache Driver
Laravel supports multiple cache backends. Pick based on your needs:
- Redis: Fast, shared across servers, but ephemeral (data lost on restart).
- File: Survives deployments, great for expensive AI API results that should persist.
- Database: When you need queryable cached data or longer retention.
For AI API responses that are expensive to regenerate, file cache is ideal:
// In config/cache.php, add a dedicated store
'stores' => [
'ai_responses' => [
'driver' => 'file',
'path' => storage_path('cache/ai'),
],
],
// Use it explicitly
Cache::store('ai_responses')->remember($key, 86400 * 7, function () {
return $this->callExpensiveAI();
});
Cache Key Best Practices
Make keys descriptive and collision-resistant:
// ❌ Too generic
$key = "data_{$id}";
// ✅ Namespaced and specific
$key = "weather:current:{$city}:" . date('Y-m-d-H');
// ✅ For complex parameters, hash them
$key = "report:" . md5(json_encode($filters));
Handling Failures
When the API fails, you have options:
return Cache::remember($key, $ttl, function () {
$response = Http::get($url);
if ($response->failed()) {
// Option 1: Return null (cache the failure briefly to avoid hammering)
Cache::put($key, null, 60); // 1 min
return null;
// Option 2: Throw exception (let it propagate, don't cache)
throw new ApiUnavailableException();
// Option 3: Return stale data if available
return Cache::get($key . ':stale');
}
return $response->json();
});
The right choice depends on your app—some can tolerate null, others need exceptions to trigger fallback logic.
When NOT to Cache
Don’t cache if the data:
- Changes constantly (real-time stock prices)
- Is user-specific and high-cardinality (unique per user ID)
- Is already fast (sub-10ms database queries)
Otherwise, cache liberally. Your API bill will thank you.
Leave a Reply