import { type DocumentNode } from "graphql"; import { type OperationVariables, ApolloClient } from "@apollo/client"; import {GraphqlRequestResult} from "@/types/graphqlFetch/type"; import {getClient} from "@/lib/ApolloClientServer"; /* 定义自己的context类型 import "@apollo/client"; import { HttpLink } from "@apollo/client"; declare module "@apollo/client" { interface DefaultContext extends HttpLink.ContextOptions {} } */ // Comprehensive error handling example. https://www.apollographql.com/docs/react/data/error-handling export type CacheLifePreset = | "seconds" | "minutes" | "hours" | "days" | "weeks" | "max"; export type CacheLifeOption = number | CacheLifePreset; export function getRevalidateTime( life?: CacheLifeOption ): number | false { if (!life) return false; if (typeof life === "number") return life; switch (life) { case "seconds": return 10; case "minutes": return 60; case "hours": return 3600; case "days": return 86400; case "weeks": return 604800; case "max": return false; default: return false; } } export function stableStringify(value: unknown): string { if (value === null || typeof value !== "object") { return JSON.stringify(value); } if (Array.isArray(value)) { return `[${value.map(stableStringify).join(",")}]`; } const obj = value as Record; return `{${Object.keys(obj) .sort() .map( (key) => `"${key}":${stableStringify(obj[key])}` ) .join(",")}}`; } export interface GraphQLRequestOptions { tags?: string[]; life?: CacheLifeOption; noCache?: boolean; context?: Record; fetchPolicy?: | "cache-first" | "network-only" | "no-cache" | "cache-only"; } export async function graphqlRequest< TData = unknown, TVariables extends OperationVariables = OperationVariables >( query: DocumentNode, variables?: TVariables, options?: GraphQLRequestOptions ): Promise> { const client = getClient(); let resData; const revalidate = getRevalidateTime(options?.life); let queryOption: ApolloClient.QueryOptions = { query, variables, fetchPolicy: "network-only", context: { fetchOptions: { next: { revalidate, tags: options?.tags, }, }, } }; if (options?.noCache) { /*** * client.query的参数是一个对象: * {query, variables, context, fetchPolicy, errorPolicy} * context.fetchOptions 可以设置nextjs fetch的缓存策略 https://www.apollographql.com/docs/react/integrations/nextjs * context: { fetchOptions: { next: { revalidate: 60, // 对应 life: 'minutes' tags: ['posts'], // 对应 tags 选项 }, }, }, */ queryOption = { query, variables, context: options?.context, fetchPolicy: "no-cache", // 跳过 apollo client 的缓存,直接调fetch }; } if (options?.context) { throw new Error( "graphqlRequest: Caching with `context` is unsafe. Use noCache instead." ); } try { // Promise-based APIs (e.g. client.query, client.mutate) - Errors either reject the promise or are returned in the result as the error field. // 如果错误被reject 则会进入catch const result: ApolloClient.QueryResult = await client.query(queryOption); resData = result.data || null; return {data: resData, error: result.error? result.error.message : '' }; } catch (error) { throw error; } } export async function graphqlRequestNoCache< TData = unknown, TVariables extends OperationVariables = OperationVariables >( query: DocumentNode, variables?: TVariables, options?: Omit< GraphQLRequestOptions, "noCache" | "tags" | "life" > ): Promise> { return graphqlRequest( query, variables, { ...options, noCache: true, } ); }