
Laravel REST API Part 8: Caching Products List with Redis
Published on Dec 12, 2024
In this tutorial, we'll walk through how to implement Redis caching for your product API in Laravel. Caching can dramatically improve performance by reducing the load on your database and making your API faster, especially when dealing with frequently accessed data like product listings.
Setting Up Redis in Laravel
If you can go back to the first episode when we installed Sail we installed Redis with it. If you open docker-compose.yml you should see something like this:
redis: image: 'redis:alpine' ports: - '${FORWARD_REDIS_PORT:-6379}:6379' volumes: - 'sail-redis:/data' networks: - sail healthcheck: test: - CMD - redis-cli - ping retries: 3 timeout: 5s
To start using Redis for caching, you first need to update the cache store in your .env file:
CACHE_DRIVER=redis
Caching Product List
Next, let's modify the code to cache the product list in the ListProductsAction. We’ll use Laravel's Cache::remember() method, which checks if a given data exists in the cache. If it does, it retrieves the data; if not, it performs the query, stores the result in the cache, and then returns the data.
You might want to check Cache::flexible for better performance, you can check it in the documentation
Let's see how to use Cache::remember(), we might update the Action class to be something like this:
<?php namespace App\Http\Actions\Product; use App\Models\Product; use Illuminate\Http\Request; use Illuminate\Support\Facades\Cache; class ListProductsAction { public function execute(Request $request) { $products = Cache::remember('products', 60 * 60, function () use ($request) { $query = Product::query(); if ($request->has("product_name")) { $query = $query->where("name", "like", $request->product_name . "%"); } if ($request->has("category_id")) { $query = $query->where("category_id", $request->category_id); } if ($request->has("price_from")) { $query = $query->where("price", '>=', $request->price_from); } if ($request->has("price_to")) { $query = $query->where("price", '<=', $request->price_to); } if ($request->has("stock_from")) { $query = $query->where("stock", '>=', $request->stock_from); } if ($request->has("stock_to")) { $query = $query->where("stock", '<=', $request->stock_to); } $query->with('category') ->orderBy('name'); return $query->paginate(); }); return $products; } }
In this code:
- 'products' is the cache key.
- 60 * 60 is the expiration time in seconds (1 hour).
- The closure function contains the query that fetches all products from the database.
Well, if you run the api you will get the result so fast until, you can test this by adding lot of records in the table.
But, what about adding filters or pagination, unfortunately that will not work well, because we use `products` as key for any kind of query. This behaviour need to be updated if we want to consider filters. We need a mechanism to make a dynamic cache key to be different with each change we have in the request params:
Le't add this function inside ListProudctsAction.php:
private function getCacheKey($request): string { $key = 'products:'; $query_params = $request->query(); ksort($query_params); $query_str = http_build_query($query_params); return $key . $query_str; }
We may update our execute function to use this key:
$cacheKey = $this->getCacheKey($request); $products = Cache::remember($cacheKey, 60 * 60, function () use ($request)
Testing
You can now test your API by applying different filters and checking that the results are cached correctly. The first time a request is made, the data will be fetched from the database and cached. On subsequent requests with the same parameters, the data will be retrieved from the cache, significantly reducing response time.
Here are some example queries:
- /api/products?name=phone
- /api/products?price_min=100&price_max=500
Conclusion
By caching the product data with Redis, you improve the performance of your API by reducing the number of database queries. This is particularly useful when you have frequent access to product listings, as caching ensures faster response times and less strain on your database.
In a production environment, caching can make a significant difference, providing a much faster and more responsive user experience.