fix: rename retried-wrapped fetch to make caching work again

This commit is contained in:
Simon Emanuelsson
2024-08-28 10:47:57 +02:00
parent 08529e6398
commit 93526ce693
41 changed files with 728 additions and 575 deletions

View File

@@ -71,7 +71,10 @@ export const accountPageQueryRouter = router({
uid,
},
{
tags: [generateRefsResponseTag(lang, uid)],
cache: "force-cache",
next: {
tags: [generateRefsResponseTag(lang, uid)],
},
}
)
@@ -132,7 +135,12 @@ export const accountPageQueryRouter = router({
locale: lang,
uid,
},
{ tags }
{
cache: "force-cache",
next: {
tags,
},
}
)
if (!response.data) {

View File

@@ -13,7 +13,11 @@ import { request } from "@/lib/graphql/request"
import { notFound } from "@/server/errors/trpc"
import { contentstackBaseProcedure, router } from "@/server/trpc"
import { generateTag } from "@/utils/generateTag"
import {
generateRefsResponseTag,
generateRefTag,
generateTag,
} from "@/utils/generateTag"
import { langInput } from "./input"
import {
@@ -82,9 +86,18 @@ export const baseQueryRouter = router({
"contentstack.contactConfig start",
JSON.stringify({ query: { lang } })
)
const response = await request<ContactConfigData>(GetContactConfig, {
locale: lang,
})
const response = await request<ContactConfigData>(
GetContactConfig,
{
locale: lang,
},
{
cache: "force-cache",
next: {
tags: [`${lang}:contact`],
},
}
)
if (!response.data) {
const notFoundError = notFound(response)
@@ -137,9 +150,18 @@ export const baseQueryRouter = router({
"contentstack.header.ref start",
JSON.stringify({ query: { lang: input.lang } })
)
const responseRef = await request<HeaderRefDataRaw>(GetCurrentHeaderRef, {
locale: input.lang,
})
const responseRef = await request<HeaderRefDataRaw>(
GetCurrentHeaderRef,
{
locale: input.lang,
},
{
cache: "force-cache",
next: {
tags: [generateRefsResponseTag(input.lang, "current_header")],
},
}
)
getHeaderCounter.add(1, { lang: input.lang })
console.info(
"contentstack.header start",
@@ -148,17 +170,17 @@ export const baseQueryRouter = router({
})
)
const currentHeaderUID =
responseRef.data.all_current_header.items[0].system.uid
// There's currently no error handling/validation for the responseRef, should it be added?
const response = await request<HeaderDataRaw>(
GetCurrentHeader,
{ locale: input.lang },
{
tags: [
generateTag(
input.lang,
responseRef.data.all_current_header.items[0].system.uid
),
],
cache: "force-cache",
next: {
tags: [generateTag(input.lang, currentHeaderUID)],
},
}
)
@@ -226,9 +248,18 @@ export const baseQueryRouter = router({
"contentstack.footer.ref start",
JSON.stringify({ query: { lang: input.lang } })
)
const responseRef = await request<FooterRefDataRaw>(GetCurrentFooterRef, {
locale: input.lang,
})
const responseRef = await request<FooterRefDataRaw>(
GetCurrentFooterRef,
{
locale: input.lang,
},
{
cache: "force-cache",
next: {
tags: [generateRefsResponseTag(input.lang, "current_footer")],
},
}
)
// There's currently no error handling/validation for the responseRef, should it be added?
getFooterCounter.add(1, { lang: input.lang })
console.info(
@@ -239,18 +270,18 @@ export const baseQueryRouter = router({
},
})
)
const currentFooterUID =
responseRef.data.all_current_footer.items[0].system.uid
const response = await request<FooterDataRaw>(
GetCurrentFooter,
{
locale: input.lang,
},
{
tags: [
generateTag(
input.lang,
responseRef.data.all_current_footer.items[0].system.uid
),
],
cache: "force-cache",
next: {
tags: [generateTag(input.lang, currentFooterUID)],
},
}
)

View File

@@ -68,7 +68,10 @@ export type Variables = {
export async function getRefsResponse<T>(query: string, variables: Variables) {
const refsResponse = await request<T>(query, variables, {
tags: [generateRefsResponseTag(variables.locale, variables.url, affix)],
cache: "force-cache",
next: {
tags: [generateRefsResponseTag(variables.locale, variables.url, affix)],
},
})
if (!refsResponse.data) {
throw notFound(refsResponse)
@@ -89,7 +92,10 @@ export async function getResponse<T>(
variables: Variables,
tags: string[]
) {
const response = await request<T>(query, variables, { tags })
const response = await request<T>(query, variables, {
cache: "force-cache",
next: { tags },
})
if (!response.data) {
throw notFound(response)
}

View File

@@ -31,7 +31,12 @@ export const contentPageQueryRouter = router({
locale: lang,
uid,
},
{ tags: [generateTag(lang, uid)] }
{
cache: "force-cache",
next: {
tags: [generateTag(lang, uid)],
},
}
)
if (!response.data) {

View File

@@ -3,7 +3,9 @@ import { metrics } from "@opentelemetry/api"
import { GetHotelPage } from "@/lib/graphql/Query/HotelPage.graphql"
import { request } from "@/lib/graphql/request"
import { notFound } from "@/server/errors/trpc"
import { contentstackBaseProcedure, router } from "@/server/trpc"
import { contentstackExtendedProcedureUID, router } from "@/server/trpc"
import { generateTag } from "@/utils/generateTag"
import { HotelPage, HotelPageDataRaw, validateHotelPageSchema } from "./output"
@@ -20,7 +22,7 @@ const getHotelPageFailCounter = meter.createCounter(
)
export const hotelPageQueryRouter = router({
get: contentstackBaseProcedure.query(async ({ ctx }) => {
get: contentstackExtendedProcedureUID.query(async ({ ctx }) => {
const { lang, uid } = ctx
getHotelPageCounter.add(1, { lang, uid: `${uid}` })
console.info(
@@ -29,10 +31,19 @@ export const hotelPageQueryRouter = router({
query: { lang, uid },
})
)
const response = await request<HotelPageDataRaw>(GetHotelPage, {
locale: lang,
uid,
})
const response = await request<HotelPageDataRaw>(
GetHotelPage,
{
locale: lang,
uid,
},
{
cache: "force-cache",
next: {
tags: [generateTag(lang, uid)],
},
}
)
if (!response.data) {
const notFoundError = notFound(response)
getHotelPageFailCounter.add(1, {

View File

@@ -71,12 +71,22 @@ async function getLanguageSwitcher(options: LanguageSwitcherVariables) {
{
document: GetDaDeEnUrlsAccountPage,
variables,
tags: tagsDaDeEn,
options: {
cache: "force-cache",
next: {
tags: tagsDaDeEn,
},
},
},
{
document: GetFiNoSvUrlsAccountPage,
variables,
tags: tagsFiNoSv,
options: {
cache: "force-cache",
next: {
tags: tagsFiNoSv,
},
},
},
])
case PageTypeEnum.currentBlocksPage:
@@ -84,12 +94,22 @@ async function getLanguageSwitcher(options: LanguageSwitcherVariables) {
{
document: GetDaDeEnUrlsCurrentBlocksPage,
variables,
tags: tagsDaDeEn,
options: {
cache: "force-cache",
next: {
tags: tagsDaDeEn,
},
},
},
{
document: GetFiNoSvUrlsCurrentBlocksPage,
variables,
tags: tagsFiNoSv,
options: {
cache: "force-cache",
next: {
tags: tagsFiNoSv,
},
},
},
])
case PageTypeEnum.loyaltyPage:
@@ -97,12 +117,22 @@ async function getLanguageSwitcher(options: LanguageSwitcherVariables) {
{
document: GetDaDeEnUrlsLoyaltyPage,
variables,
tags: tagsDaDeEn,
options: {
cache: "force-cache",
next: {
tags: tagsDaDeEn,
},
},
},
{
document: GetFiNoSvUrlsLoyaltyPage,
variables,
tags: tagsFiNoSv,
options: {
cache: "force-cache",
next: {
tags: tagsFiNoSv,
},
},
},
])
case PageTypeEnum.hotelPage:
@@ -110,12 +140,22 @@ async function getLanguageSwitcher(options: LanguageSwitcherVariables) {
{
document: GetDaDeEnUrlsHotelPage,
variables,
tags: tagsDaDeEn,
options: {
cache: "force-cache",
next: {
tags: tagsDaDeEn,
},
},
},
{
document: GetFiNoSvUrlsHotelPage,
variables,
tags: tagsFiNoSv,
options: {
cache: "force-cache",
next: {
tags: tagsFiNoSv,
},
},
},
])
case PageTypeEnum.contentPage:
@@ -123,12 +163,22 @@ async function getLanguageSwitcher(options: LanguageSwitcherVariables) {
{
document: GetDaDeEnUrlsContentPage,
variables,
tags: tagsDaDeEn,
options: {
cache: "force-cache",
next: {
tags: tagsDaDeEn,
},
},
},
{
document: GetFiNoSvUrlsContentPage,
variables,
tags: tagsFiNoSv,
options: {
cache: "force-cache",
next: {
tags: tagsFiNoSv,
},
},
},
])

View File

@@ -73,7 +73,10 @@ export const loyaltyPageQueryRouter = router({
uid,
},
{
tags: [generateRefsResponseTag(lang, uid)],
cache: "force-cache",
next: {
tags: [generateRefsResponseTag(lang, uid)],
},
}
)
@@ -146,7 +149,12 @@ export const loyaltyPageQueryRouter = router({
locale: lang,
uid,
},
{ tags }
{
cache: "force-cache",
next: {
tags,
},
}
)
if (!response.data) {

View File

@@ -45,12 +45,8 @@ const page = z.object({
export type Page = z.infer<typeof page>
const metaDataItems = z.object({
items: z.array(page),
})
export const validateMyPagesMetaDataContentstackSchema = z.object({
all_account_page: metaDataItems,
account_page: page,
})
export type GetMyPagesMetaDataData = z.infer<
@@ -58,7 +54,7 @@ export type GetMyPagesMetaDataData = z.infer<
>
export const validateLoyaltyPageMetaDataContentstackSchema = z.object({
all_loyalty_page: metaDataItems,
loyalty_page: page,
})
export type GetLoyaltyPageMetaDataData = z.infer<

View File

@@ -1,6 +1,6 @@
import { GetLoyaltyPageMetaData } from "@/lib/graphql/Query/MetaDataLoyaltyPage.graphql"
import { GetMyPagesMetaData } from "@/lib/graphql/Query/MetaDataMyPages.graphql"
import { contentstackBaseProcedure, router } from "@/server/trpc"
import { contentstackExtendedProcedureUID, router } from "@/server/trpc"
import {
type GetLoyaltyPageMetaDataData,
@@ -8,7 +8,7 @@ import {
validateLoyaltyPageMetaDataContentstackSchema,
validateMyPagesMetaDataContentstackSchema,
} from "./output"
import { getMetaData, getResponse, Variables } from "./utils"
import { getMetaData, getResponse, type Variables } from "./utils"
import { PageTypeEnum } from "@/types/requests/pageType"
@@ -23,13 +23,13 @@ async function getLoyaltyPageMetaData(variables: Variables) {
if (!validatedMetaDataData.success) {
console.error(
`Failed to validate Loyaltypage MetaData Data - (url: ${variables.url})`
`Failed to validate Loyaltypage MetaData Data - (uid: ${variables.uid})`
)
console.error(validatedMetaDataData.error)
return null
}
return getMetaData(validatedMetaDataData.data.all_loyalty_page.items[0])
return getMetaData(validatedMetaDataData.data.loyalty_page)
}
async function getMyPagesMetaData(variables: Variables) {
@@ -43,24 +43,20 @@ async function getMyPagesMetaData(variables: Variables) {
if (!validatedMetaDataData.success) {
console.error(
`Failed to validate My Page MetaData Data - (url: ${variables.url})`
`Failed to validate My Page MetaData Data - (uid: ${variables.uid})`
)
console.error(validatedMetaDataData.error)
return null
}
return getMetaData(validatedMetaDataData.data.all_account_page.items[0])
return getMetaData(validatedMetaDataData.data.account_page)
}
export const metaDataQueryRouter = router({
get: contentstackBaseProcedure.query(async ({ ctx }) => {
if (!ctx.uid) {
return []
}
get: contentstackExtendedProcedureUID.query(async ({ ctx }) => {
const variables = {
locale: ctx.lang,
url: ctx.pathname,
uid: ctx.uid,
}
switch (ctx.contentType) {
@@ -69,7 +65,7 @@ export const metaDataQueryRouter = router({
case PageTypeEnum.loyaltyPage:
return await getLoyaltyPageMetaData(variables)
default:
return []
return null
}
}),
})

View File

@@ -2,15 +2,22 @@ import { Lang } from "@/constants/languages"
import { request } from "@/lib/graphql/request"
import { internalServerError, notFound } from "@/server/errors/trpc"
import { generateTag } from "@/utils/generateTag"
import { getMetaDataSchema, Page } from "./output"
export type Variables = {
locale: Lang
url: string
uid: string
}
export async function getResponse<T>(query: string, variables: Variables) {
const response = await request<T>(query, variables)
const response = await request<T>(query, variables, {
cache: "force-cache",
next: {
tags: [generateTag(variables.locale, variables.uid)],
},
})
if (!response.data) {
throw notFound(response)
}

View File

@@ -13,19 +13,15 @@ import {
generateTag,
generateTags,
} from "@/utils/generateTag"
import { removeMultipleSlashes } from "@/utils/url"
import {
type GetNavigationMyPagesData,
type GetNavigationMyPagesRefsData,
getNavigationSchema,
type MenuItems,
navigationPayloadSchema,
navigationRefsPayloadSchema,
} from "./output"
import { getConnections } from "./utils"
import { PageLinkEnum } from "@/types/requests/pageLinks"
import { getConnections, mapMenuItems } from "./utils"
const meter = metrics.getMeter("trpc.navigationMyPages")
const getNavigationMyPagesRefsCounter = meter.createCounter(
@@ -47,39 +43,6 @@ const getNavigationMyPagesFailCounter = meter.createCounter(
"trpc.contentstack.navigationMyPages.get-fail"
)
export function mapMenuItems(menuItems: MenuItems) {
return menuItems.map((menuItem) => {
return {
...menuItem,
links: menuItem.links
.filter((link) => {
// If content is unpublished or in other way inaccessible in Contentstack
// there will be no edges, filter out those links.
return !!link.page.edges[0]
})
.map((link) => {
const page = link.page.edges[0].node
let originalUrl = undefined
if (
page.__typename === PageLinkEnum.ContentPage ||
page.__typename === PageLinkEnum.LoyaltyPage
) {
if (page.web.original_url) {
originalUrl = page.web.original_url
}
}
return {
lang: page.system.locale,
linkText: link.link_text ? link.link_text : page.title,
uid: page.system.uid,
url: removeMultipleSlashes(`/${page.system.locale}/${page.url}`),
originalUrl,
}
}),
}
})
}
export const navigationQueryRouter = router({
get: contentstackBaseProcedure.query(async function ({ ctx }) {
const { lang } = ctx
@@ -92,7 +55,10 @@ export const navigationQueryRouter = router({
GetNavigationMyPagesRefs,
{ locale: lang },
{
tags: [generateRefsResponseTag(lang, "navigation_my_pages")],
cache: "force-cache",
next: {
tags: [generateRefsResponseTag(lang, "navigation_my_pages")],
},
}
)
@@ -157,7 +123,10 @@ export const navigationQueryRouter = router({
const response = await request<GetNavigationMyPagesData>(
GetNavigationMyPages,
{ locale: lang },
{ tags }
{
cache: "force-cache",
next: { tags },
}
)
if (!response.data) {

View File

@@ -1,6 +1,9 @@
import { removeMultipleSlashes } from "@/utils/url"
import { PageLinkEnum } from "@/types/requests/pageLinks"
import type { Edges } from "@/types/requests/utils/edges"
import type { NodeRefs } from "@/types/requests/utils/refs"
import type { GetNavigationMyPagesRefsData } from "./output"
import type { GetNavigationMyPagesRefsData, MenuItems } from "./output"
export function getConnections(refs: GetNavigationMyPagesRefsData) {
const connections: Edges<NodeRefs>[] = []
@@ -14,3 +17,36 @@ export function getConnections(refs: GetNavigationMyPagesRefsData) {
return connections
}
export function mapMenuItems(menuItems: MenuItems) {
return menuItems.map((menuItem) => {
return {
...menuItem,
links: menuItem.links
.filter((link) => {
// If content is unpublished or in other way inaccessible in Contentstack
// there will be no edges, filter out those links.
return !!link.page.edges[0]
})
.map((link) => {
const page = link.page.edges[0].node
let originalUrl = undefined
if (
page.__typename === PageLinkEnum.ContentPage ||
page.__typename === PageLinkEnum.LoyaltyPage
) {
if (page.web.original_url) {
originalUrl = page.web.original_url
}
}
return {
lang: page.system.locale,
linkText: link.link_text ? link.link_text : page.title,
uid: page.system.uid,
url: removeMultipleSlashes(`/${page.system.locale}/${page.url}`),
originalUrl,
}
}),
}
})
}

View File

@@ -25,7 +25,7 @@ const getHotelSuccessCounter = meter.createCounter("trpc.hotel.get-success")
const getHotelFailCounter = meter.createCounter("trpc.hotel.get-fail")
export const hotelQueryRouter = router({
getHotel: serviceProcedure
get: serviceProcedure
.input(getHotelInputSchema)
.query(async ({ ctx, input }) => {
const { hotelId, language, include } = input
@@ -152,62 +152,69 @@ export const hotelQueryRouter = router({
roomCategories: roomCategories,
}
}),
getRates: publicProcedure
.input(getRatesInputSchema)
.query(async ({ input, ctx }) => {
// TODO: Do a real API call when the endpoint is ready
// const { hotelId } = input
rates: router({
get: publicProcedure
.input(getRatesInputSchema)
.query(async ({ input, ctx }) => {
// TODO: Do a real API call when the endpoint is ready
// const { hotelId } = input
// const params = new URLSearchParams()
// const apiLang = toApiLang(language)
// params.set("hotelId", hotelId.toString())
// params.set("language", apiLang)
// const params = new URLSearchParams()
// const apiLang = toApiLang(language)
// params.set("hotelId", hotelId.toString())
// params.set("language", apiLang)
console.info("api.hotels.rates start", JSON.stringify({}))
const validatedHotelData = getRatesSchema.safeParse(tempRatesData)
console.info("api.hotels.rates start", JSON.stringify({}))
const validatedHotelData = getRatesSchema.safeParse(tempRatesData)
if (!tempRatesData) {
console.error("api.hotels.rates error", JSON.stringify({ error: null }))
//Can't return null here since consuming component does not handle null yet
// return null
}
if (!validatedHotelData.success) {
console.error(
"api.hotels.rates validation error",
JSON.stringify({
error: validatedHotelData.error,
})
)
throw badRequestError()
}
console.info("api.hotels.rates success", JSON.stringify({}))
return validatedHotelData.data
}),
getFilters: publicProcedure
.input(getFiltersInputSchema)
.query(async ({ input, ctx }) => {
console.info("api.hotels.filters start", JSON.stringify({}))
if (!tempRatesData) {
console.error(
"api.hotels.rates error",
JSON.stringify({ error: null })
)
//Can't return null here since consuming component does not handle null yet
// return null
}
if (!validatedHotelData.success) {
console.error(
"api.hotels.rates validation error",
JSON.stringify({
error: validatedHotelData.error,
})
)
throw badRequestError()
}
console.info("api.hotels.rates success", JSON.stringify({}))
return validatedHotelData.data
}),
}),
filters: router({
get: publicProcedure
.input(getFiltersInputSchema)
.query(async ({ input, ctx }) => {
console.info("api.hotels.filters start", JSON.stringify({}))
if (!tempFilterData) {
console.error(
"api.hotels.filters error",
JSON.stringify({ error: null })
)
//Can't return null here since consuming component does not handle null yet
// return null
}
const validateFilterData = getFiltersSchema.safeParse(tempFilterData)
if (!tempFilterData) {
console.error(
"api.hotels.filters error",
JSON.stringify({ error: null })
)
//Can't return null here since consuming component does not handle null yet
// return null
}
const validateFilterData = getFiltersSchema.safeParse(tempFilterData)
if (!validateFilterData.success) {
console.error(
"api.hotels.filters validation error",
JSON.stringify({
error: validateFilterData.error,
})
)
throw badRequestError()
}
console.info("api.hotels.rates success", JSON.stringify({}))
return validateFilterData.data
}),
if (!validateFilterData.success) {
console.error(
"api.hotels.filters validation error",
JSON.stringify({
error: validateFilterData.error,
})
)
throw badRequestError()
}
console.info("api.hotels.rates success", JSON.stringify({}))
return validateFilterData.data
}),
}),
})