Merged in feat/sw-2863-move-contentstack-router-to-trpc-package (pull request #2389)
feat(SW-2863): Move contentstack router to trpc package * Add exports to packages and lint rule to prevent relative imports * Add env to trpc package * Add eslint to trpc package * Apply lint rules * Use direct imports from trpc package * Add lint-staged config to trpc * Move lang enum to common * Restructure trpc package folder structure * WIP first step * update internal imports in trpc * Fix most errors in scandic-web Just 100 left... * Move Props type out of trpc * Fix CategorizedFilters types * Move more schemas in hotel router * Fix deps * fix getNonContentstackUrls * Fix import error * Fix entry error handling * Fix generateMetadata metrics * Fix alertType enum * Fix duplicated types * lint:fix * Merge branch 'master' into feat/sw-2863-move-contentstack-router-to-trpc-package * Fix broken imports * Merge branch 'master' into feat/sw-2863-move-contentstack-router-to-trpc-package Approved-by: Linus Flood
This commit is contained in:
147
packages/trpc/lib/graphql/_request.ts
Normal file
147
packages/trpc/lib/graphql/_request.ts
Normal file
@@ -0,0 +1,147 @@
|
||||
import "server-only"
|
||||
|
||||
import { ClientError, type GraphQLClient } from "graphql-request"
|
||||
|
||||
import { Lang } from "@scandic-hotels/common/constants/language"
|
||||
|
||||
import { env } from "../../env/server"
|
||||
|
||||
import type { DocumentNode } from "graphql"
|
||||
|
||||
import type { Data } from "../types/requestData"
|
||||
|
||||
export async function request<T>(
|
||||
client: GraphQLClient,
|
||||
query: string | DocumentNode,
|
||||
variables?: {},
|
||||
params?: RequestInit
|
||||
): Promise<Data<T>> {
|
||||
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
|
||||
|
||||
if (env.PRINT_QUERY) {
|
||||
const print = (await import("graphql/language/printer")).print
|
||||
const rawResponse = await client.rawRequest<T>(
|
||||
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: "<Unable to extract>",
|
||||
variables,
|
||||
})
|
||||
}
|
||||
|
||||
const response = await client.request<T>({
|
||||
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
|
||||
|
||||
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: "<Unable to extract>",
|
||||
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")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user