import "server-only" import { ClientError, type GraphQLClient } from "graphql-request" import { Lang } from "@scandic-hotels/common/constants/language" import { createLogger } from "@scandic-hotels/common/logger/createLogger" import { env } from "../../env/server" import type { DocumentNode } from "graphql" import type { Data } from "../types/requestData" const requestLogger = createLogger("graphql-request") export async function request( client: GraphQLClient, query: string | DocumentNode, variables?: {}, params?: RequestInit ): Promise> { try { client.setHeaders({ access_token: env.CMS_ACCESS_TOKEN, branch: env.CMS_BRANCH, "Content-Type": "application/json", ...params?.headers, }) client.requestConfig.cache = params?.cache client.requestConfig.next = params?.next 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 requestLogger.debug(`[gql] Sending graphql request to ${env.CMS_URL}`, { operationName, variables, }) } catch (e) { requestLogger.error(`[gql] Unable to extract operation name from query`, { query, error: e, }) requestLogger.debug(`[gql] Sending graphql request to ${env.CMS_URL}`, { operationName: "", variables, }) } const response = await client.request({ document: query, variables, requestHeaders: { "User-Agent": `scandic-web-${env.SENTRY_ENVIRONMENT}`, }, }) 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 requestLogger.debug(`[gql] Response for ${env.CMS_URL}`, { response, operationName, variables, }) } catch (e) { requestLogger.error(`[gql] Unable to extract operation name from query`, { query, error: e, }) requestLogger.debug(`[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 } } } } requestLogger.error( `[gql] Error sending graphql request to ${env.CMS_URL}`, error ) throw new Error("Failed to fetch data from CMS", { cause: { error } }) } }