import "server-only" import { ClientError, GraphQLClient } from "graphql-request" import { Lang } from "@/constants/languages" import { env } from "@/env/server" import type { DocumentNode } from "graphql" import type { Data } from "@/types/request" export async function request( client: GraphQLClient, query: string | DocumentNode, variables?: {}, params?: RequestInit ): Promise> { try { client.setHeaders({ access_token: env.CMS_ACCESS_TOKEN, "Content-Type": "application/json", ...params?.headers, }) client.requestConfig.cache = params?.cache client.requestConfig.next = params?.next if (env.PRINT_QUERY) { const print = (await import("graphql/language/printer")).print const rawResponse = await client.rawRequest( print(query as DocumentNode), variables, { access_token: env.CMS_ACCESS_TOKEN, "Content-Type": "application/json", } ) /** * TODO: Send to Monitoring (Logging and Metrics) */ console.log({ complexityLimit: rawResponse.headers.get("x-query-complexity"), }) console.log({ referenceDepth: rawResponse.headers.get("x-reference-depth"), }) console.log({ resolverCost: rawResponse.headers.get("x-resolver-cost"), }) return { data: rawResponse.data, } } try { // @ts-expect-error: query can be undefined (?) const operationName = (query as DocumentNode).definitions.find( (d) => d.kind === "OperationDefinition" && d.operation === "query" // @ts-expect-error: name does not exist (?) ).name.value console.log(`[gql] Sending graphql request to ${env.CMS_URL}`, { operationName, variables, }) } catch (e) { console.error(`[gql] Unable to extract operation name from query`, { query, error: e, }) console.log(`[gql] Sending graphql request to ${env.CMS_URL}`, { operationName: "", variables, }) } const response = await client.request({ document: query, variables, }) try { // @ts-expect-error: query can be undefined (?) const operationName = (query as DocumentNode).definitions.find( (d) => d.kind === "OperationDefinition" && d.operation === "query" // @ts-expect-error: name does not exist (?) ).name.value console.log(`[gql] Response for ${env.CMS_URL}`, { response, operationName, variables, }) } catch (e) { console.error(`[gql] Unable to extract operation name from query`, { query, error: e, }) console.log(`[gql] Response for ${env.CMS_URL}`, { response, operationName: "", variables, }) } return { data: response } } catch (error) { if (error instanceof ClientError) { if (error.response.errors?.length) { const failedToFetchItem = error.response.errors.find( (err) => err.message === "Failed to fetch item" ) if ( failedToFetchItem && failedToFetchItem.extensions?.errors === "Object not found!" && failedToFetchItem.path?.find((p) => Lang[p as Lang]) ) { /** * Because of Contentstacks totally obscure way of implementing * GraphQL where they throw an error when you are querying for * a single item that is nullable and doesn't exist. This leads * to the issue where when we have a page that is missing a published * version for one language, it throws an error which we have to recover * from here since it isn't an error. */ return { data: error.response.data as T } } } } console.error( `[gql] Error sending graphql request to ${env.CMS_URL}`, error ) throw new Error("Something went wrong") } }