CSR Cache & Next.js
เบราว์เซอร์ cache ใช้ createCsrCache ของ Core และจะเพิ่ม /next ของ callApiSsrCache เมื่อจำเป็นต้องใช้ Data Cache ของเซิร์ฟเวอร์ Next.js เท่านั้น
cache wrapper ก็เป็นส่วนหนึ่งของ commonService
โค้ด callApiClientCache/callApiServerCache ของหน้านี้อธิบายเฉพาะส่วน cache ของ HTTP adapter ที่ใช้ร่วมกันในโปรเจกต์ สามารถกำหนดให้บริการที่สร้างขึ้นนำเข้าฟังก์ชันนี้ได้ ดังนั้นการดูโครงสร้างทั้งหมดของ rxjsHttpService.ts/commonService.ts ก่อนจะทำให้เห็นตำแหน่งและบทบาทของแต่ละ wrapper ได้ชัดเจนขึ้น
CSR cache (cache ของไคลเอนต์)
createCsrCache<CacheName>()มี callApiCsrCache(callApiFn, serviceArgs, cacheOptions) และ removeCsrCache(cacheName) ให้บริการ
import {
createCsrCache,
type ServiceArguments,
} from "@byeolnaerim/typed-rx-http";
import type { paths as Paths } from "./@types/ApiTypes";
type CacheNames = "adminList" | "profile";
const csrCache = createCsrCache<CacheNames>();
export const callApiClientCache = <R>(
args: ServiceArguments<Paths, any, any, R>,
cache: {
cacheName: CacheNames;
cacheTime: number;
cacheSize?: number;
},
) => csrCache.callApiCsrCache(
client.callApi,
args as any,
cache as any,
);
csrCache.removeCsrCache("adminList");
csrCache.removeCsrCache("any-prefix");ในสภาพแวดล้อมของเซิร์ฟเวอร์จะไม่สร้าง CSR cache map และเรียกใช้ callApi ตามปกติ ในเบราว์เซอร์จะใช้ shareReplay เพื่อแชร์ผลลัพธ์ของ Observable ที่มี cache key เดียวกัน
Next.js adapter: callApiSsrCache
เป็น SSR helper ที่ใช้ next/cache(unstable_cache) ของ Next.js หากเป็น GET และ cacheTime > 0 จะใช้ force-cache + revalidate และคำขออื่น ๆ จะดำเนินการด้วย no-store
- สามารถฉีด Cookie/Authorization ตามคำขอได้ด้วย headersProvider
- จะดำเนินการเมื่อมี onServer401 ที่ 401
import type { paths as Paths } from "./@types/ApiTypes";
import { firstValueFrom } from "rxjs";
import {
callApiSsrCache,
redirectToUnauthorizedOnServer401,
} from "@byeolnaerim/typed-rx-http/next";
const apiUrl = process.env.NEXT_PUBLIC_API_URL!;
const headersProvider = async () => {
const { cookies } = await import("next/headers");
const cookieStore = await cookies();
const cookieHeader = cookieStore
.getAll()
.map((c) => `${c.name}=${c.value}`)
.join("; ");
const accessToken = cookieStore.get("accessToken")?.value;
return {
...(cookieHeader ? { Cookie: cookieHeader } : {}),
...(accessToken
? { Authorization: `Bearer ${accessToken}` }
: {}),
};
};
const obs$ = callApiSsrCache<Paths, { ok: true }, "adminList">({
baseUrl: apiUrl,
serviceArguments: { url: "/api/secure", method: "get" },
cacheForService: { cacheName: "adminList", cacheTime: 10_000 },
headersProvider,
onServer401: redirectToUnauthorizedOnServer401,
});
const res = await firstValueFrom(obs$);ไม่ทำการ cache ข้อมูลตามผู้ใช้
เมื่อรวมเบราว์เซอร์/เซิร์ฟเวอร์เป็น wrapper โปรเจกต์เดียว
ในบริการที่ใช้ร่วมกัน เบราว์เซอร์สามารถรวมให้ใช้ createCsrCache และเซิร์ฟเวอร์ใช้ callApiSsrCache ได้ นี่เป็นรูปแบบการจัดโครงสร้างโปรเจกต์และไม่ใช่โครงสร้างที่จำเป็นของ Core เอง
commonService.ts
tsconst csrCache = createCsrCache<"memberList" | "profile">();
export const callApiClientCache = (
serviceArguments,
cacheForService,
) => csrCache.callApiCsrCache(
callApi,
serviceArguments,
cacheForService,
);
export const removeCsrCache = csrCache.removeCsrCache;commonService.ts
tsexport const callApiServerCache = (serviceArguments, cacheForService) => {
if (typeof window !== "undefined") {
return callApiClientCache(serviceArguments, cacheForService);
}
return from(
import("@byeolnaerim/typed-rx-http/next"),
).pipe(
mergeMap(({ callApiSsrCache }) =>
callApiSsrCache({
baseUrl: process.env.NEXT_PUBLIC_API_URL || "",
serviceArguments,
cacheForService,
headersProvider,
}),
),
);
};เมื่อใช้ cache wrapper ในบริการที่สร้างขึ้นอัตโนมัติ ให้เชื่อมต่อ wrapper นี้เฉพาะกับ endpoint ที่ต้องการฟังก์ชัน cache เท่านั้น ส่วนที่เหลือใช้ callApi ตามปกติ