CSRキャッシュ & Next.js

ブラウザキャッシュは Core の createCsrCache を使用し、Next.js サーバーのデータキャッシュが必要なときだけ /next の callApiSsrCache を追加します。


キャッシュラッパーも commonService の一部です。

このページの callApiClientCache/callApiServerCache コードは、プロジェクト共通 HTTP アダプターのキャッシュ部分だけを説明します。生成されたサービスがこの関数をインポートするように構成できるため、全体の rxjsHttpService.ts/commonService.ts 構造を最初に見ると、各ラッパーの位置と役割がより明確になります。

CSR キャッシュ (クライアントキャッシュ)

createCsrCache<CacheName>()は callApiCsrCache(callApiFn, serviceArgs, cacheOptions) と removeCsrCache(cacheName) を提供します。

ts
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 キャッシュマップを作成せず、元の callApi をそのまま呼び出します。ブラウザでは同じキャッシュキーの Observable 結果を shareReplay で共有します。

Next.js アダプター: callApiSsrCache

Next.js の next/cache(unstable_cache) を使用する SSR ヘルパーです。GET で cacheTime > 0 の場合は force-cache + revalidate を使用し、それ以外のリクエストは no-store で実行します。

  • headersProvider でリクエストごとに Cookie/Authorization を注入できます。
  • 401 で onServer401 があれば実行します。
ts
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$);

ユーザーごとのデータはキャッシュしない

ブラウザ/サーバーを 1 つのプロジェクトラッパーでまとめる場合

共通サービスでブラウザは createCsrCache、サーバーは callApiSsrCache に分岐するようにまとめることもできます。これはプロジェクト構成パターンであり、Core 自体の必須構造ではありません。

commonService.ts
ts
const csrCache = createCsrCache<"memberList" | "profile">();

export const callApiClientCache = (
  serviceArguments,
  cacheForService,
) => csrCache.callApiCsrCache(
  callApi,
  serviceArguments,
  cacheForService,
);

export const removeCsrCache = csrCache.removeCsrCache;
commonService.ts
ts
export 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,
      }),
    ),
  );
};

自動生成サービスでキャッシュラッパーを使用する場合も、キャッシュ機能が必要なエンドポイントにのみこのラッパーを接続し、残りは通常の callApi をそのまま使用します。

© 2026 Byeolnaerim. 無断転載を禁じます。紹介プライバシーポリシー