Next.js framework thành công kết hợp server-side rendering (SSR) và static site generation (SSG). SSG tăng tốc website nhờ CDN caching, SSR giúp SEO và dynamic data.
SSR tính năng tuyệt vời giúp viết full-stack apps. Nhưng nếu không cẩn thận, performance Next.js website dễ bị ảnh hưởng. Bài viết này giải thích cách dùng Redis speed up Next.js API calls. Trước đó nhắc sơ qua cách đơn giản hơn cải thiện performance.
Dùng SWR cho API calls
SWR thư viện data fetching thông minh. Sử dụng HTTP cache invalidation strategy (stale-while-revalidate) theo HTTP RFC 5861. Gọi API với SWR, nó trả cached data ngay lập tức nhưng asynchronously fetch current data và update UI. Có thể set refreshInterval tùy tolerance staleness.
const { data: user } = useSWR('/api/user', { refreshInterval: 2000 })
Trên code, user API refresh mỗi 2 giây.
Caching với Redis
SWR đơn giản và hiệu quả. Nhưng có cases cần server-side caching:
- Client-side caching cải thiện performance cho clients. Nhưng nếu số client lớn, server-side resources bị load cao, cuối cùng ảnh hưởng client-side performance.
- Nếu consume external API có quota, muốn control API usage server-side. Không thì quá nhiều clients consume API nhanh chóng.
- Nếu resources calculated/fetched/processed server-side dùng dynamic inputs, client-side caching không hữu ích.
Example Project: Covid Tracker
Dùng Javier Aviles' Covid API tìm top 10 countries most cases. Xem website và source code.
Dùng Redis cache responses từ Covid API để:
- Response nhanh hơn nhiều. Check website, gọi Covid API hàng trăm ms, fetch từ Redis 1-2ms.
- Không overwhelm Covid API với quá nhiều requests.
API Code
Code check cache trong Redis trước. Nếu không có, lấy all country list từ Covid API, sort theo today cases, lưu top 10 vào Redis. Set "EX" 60 nghĩa là Redis evict entry sau 60 giây.
import Redis from "ioredis";
let redis = new Redis(process.env.REDIS_URL);
export default async (req, res) => {
let start = Date.now();
let cache = await redis.get("cache");
cache = JSON.parse(cache);
let result = {};
if (cache) {
console.log("loading from cache");
result.data = cache;
result.type = "redis";
result.latency = Date.now() - start;
return res.status(200).json(result);
} else {
console.log("loading from api");
start = Date.now();
return fetch("https://coronavirus-19-api.herokuapp.com/countries")
.then((r) => r.json())
.then((data) => {
data.sort(function (a, b) { return b.todayCases - a.todayCases; });
result.data = data.splice(1, 11);
result.type = "api";
result.latency = Date.now() - start;
redis.set("cache", JSON.stringify(result.data), "EX", 60);
return res.status(200).json(result);
});
}
};
UI Code
UI React đơn giản. Fetch data từ API dùng SWR.
export default function Home() {
function refresh(e) { e.preventDefault(); window.location.reload(); }
const { data, error } = useSWR("api/data", fetcher);
if (error) return "An error has occurred.";
if (!data) return "Loading...";
return (
Covid Tracker
Covid Tracker
Top 10 countries with the most cases today
Country Today Cases Today Deaths
{data.data.map((item) => (
{item.country} {item.todayCases} {item.todayDeaths}
))}
Loaded from {data.type} in {data.latency} milliseconds. Click to reload.
);
}