Rewriting at the edge using Upstash
It's a common case to have a details page of a product or item and request our database for stock every time a user requests the page (even if our page is using ISR and we fetch the stock client side).
Sometimes we don't have stock but we still hit our DB (API then DB if doing CSR), which can take a good amount of time depending on where the source and our API are and it can be expensive depending on how many requests for that page we have.
We can get faster responses using the edge, by storing and checking in Redis if we have ran out of stock for a product and rewriting to a previously generated static no-stock page for that specific product. That way we reduce the amount of connections to our database, avoid uninteractive page due to disabled buy buttons while checking stock and reduce content changes when the UI has to change if there's no stock, all while having low latency by embracing the edge.
Imagine the next flow of an e-commerce site product details page:
Now, lets check at the edge if we have stock using Upstash (a Redis service) and rewrite to the correct page:
Thats it, we only have to toggle the flag when we add an item or run out of stock.
Implementing the solution
For this example we will have 3 files related to the product details page. /pages/product/[id]/no-stock.js
, /pages/product/[id]/index.js
and /middleware.js
.
Lets start with our /pages/product/[id]/index.js
:
export const getStaticProps = async ({params}) => { const product = await api.fetch(params.id) if (!product) { return { notFound: true } } return { revalidate: 10, props: { product } } }
This way we render the product is found or redirect the user to a 404 page otherwise.
Now lets handle the rewrite logic in /middleware.js
:
import { NextResponse } from 'next/server' import api from './api' export const config = { matcher: '/product/:path', } export async function middleware(req) { // Extract id from pathname const [, , id] = req.nextUrl.pathname.split('/') // Check on upstash if we have stock const hasStock = await api.cache.get(id) // Rewrite to the correct url req.nextUrl.pathname = hasStock ? `/product/${id}/` : `/product/${id}/no-stock` // Return rewrited path return NextResponse.rewrite(req.nextUrl) }
Now we will only get to the details screen if we have stock.
Go to this products and play around with their stock and you will be rewrited to the correct page.