feat(SW-186): Added refs and some extra querys

This commit is contained in:
Erik Tiekstra
2024-09-05 09:25:21 +02:00
parent 52fdc1daac
commit 55fdbc527b
11 changed files with 388 additions and 303 deletions

View File

@@ -268,24 +268,26 @@ export type FooterRefDataRaw = z.infer<typeof validateFooterRefConfigSchema>
const linkConnectionNodeSchema = z
.object({
edges: z.array(
z.object({
node: z.object({
system: z.object({
uid: z.string(),
locale: z.nativeEnum(Lang),
edges: z
.array(
z.object({
node: z.object({
system: z.object({
uid: z.string(),
locale: z.nativeEnum(Lang),
}),
url: z.string(),
title: z.string(),
web: z.object({
original_url: z.string(),
}),
}),
url: z.string(),
title: z.string(),
web: z.object({
original_url: z.string().nullable().optional(),
}),
}),
})
),
})
)
.max(1),
})
.transform((rawData) => {
const node = rawData.edges[0]?.node
.transform((data) => {
const node = data.edges[0]?.node
if (!node) {
return null
}
@@ -301,15 +303,14 @@ const linkConnectionNodeSchema = z
const linkWithTitleSchema = z
.object({
title: z.string().nullable(),
title: z.string(),
linkConnection: linkConnectionNodeSchema,
})
.transform((rawData) => {
return rawData.linkConnection && rawData.title
? {
...rawData.linkConnection,
title: rawData.title,
href: rawData.linkConnection.href,
isExternal: rawData.linkConnection.isExternal,
}
: null
})
@@ -325,21 +326,18 @@ const cardButtonSchema = z
linkConnection: linkConnectionNodeSchema,
open_in_new_tab: z.boolean(),
})
.transform((rawData) => {
if (!rawData) {
return null
}
const linkConnectionData = rawData.linkConnection
const isContentstackLink = rawData.is_contentstack_link
const externalLink = rawData.external_link
.transform((data) => {
const linkConnectionData = data.linkConnection
const isContentstackLink = data.is_contentstack_link
const externalLink = data.external_link
const href =
isContentstackLink && externalLink.href
? externalLink.href
: linkConnectionData?.href || ""
return {
openInNewTab: rawData.open_in_new_tab,
title: rawData.cta_text,
openInNewTab: data.open_in_new_tab,
title: data.cta_text,
href,
isExternal: !isContentstackLink || linkConnectionData?.isExternal,
}
@@ -347,23 +345,25 @@ const cardButtonSchema = z
const cardConnectionSchema = z
.object({
edges: z.array(
z.object({
node: z.object({
heading: z.string(),
body_text: z.string(),
background_image: imageVaultAssetTransformedSchema,
has_primary_button: z.boolean(),
has_secondary_button: z.boolean(),
scripted_top_title: z.string(),
primary_button: cardButtonSchema,
secondary_button: cardButtonSchema,
}),
})
),
edges: z
.array(
z.object({
node: z.object({
heading: z.string(),
body_text: z.string(),
background_image: imageVaultAssetTransformedSchema,
has_primary_button: z.boolean(),
has_secondary_button: z.boolean(),
scripted_top_title: z.string(),
primary_button: cardButtonSchema.nullable(),
secondary_button: cardButtonSchema.nullable(),
}),
})
)
.max(1),
})
.transform((rawData) => {
const node = rawData.edges[0]?.node
.transform((data) => {
const node = data.edges[0]?.node
if (!node) {
return null
}
@@ -391,31 +391,33 @@ export const menuItemSchema = z
see_all_link: linkWithTitleSchema,
cardConnection: cardConnectionSchema,
})
.transform(
({ submenu, linkConnection, cardConnection, see_all_link, title }) => {
return {
title,
link: submenu.length ? null : linkConnection,
seeAllLink: submenu.length ? see_all_link : null,
submenu,
card: cardConnection,
}
.transform((data) => {
const { submenu, linkConnection, cardConnection, see_all_link, title } =
data
return {
title,
link: submenu.length ? null : linkConnection,
seeAllLink: submenu.length ? see_all_link : null,
submenu,
card: cardConnection,
}
)
})
export const getHeaderSchema = z
.object({
all_header: z.object({
items: z.array(
z.object({
top_link: linkWithTitleSchema.nullable(),
menu_items: z.array(menuItemSchema).nullable(),
})
),
items: z
.array(
z.object({
top_link: linkWithTitleSchema,
menu_items: z.array(menuItemSchema),
})
)
.length(1),
}),
})
.transform((rawData) => {
const { top_link, menu_items } = rawData.all_header.items[0]
.transform((data) => {
const { top_link, menu_items } = data.all_header.items[0]
return {
topLink: top_link,
@@ -423,15 +425,78 @@ export const getHeaderSchema = z
}
})
export const getHeaderRefSchema = z.object({
all_header: z.object({
items: z.array(
const linkConnectionRefs = z.object({
edges: z
.array(
z.object({
system: z.object({
content_type_uid: z.string(),
uid: z.string(),
node: z.object({
system: z.object({
content_type_uid: z.string(),
uid: z.string(),
}),
}),
})
),
)
.max(1),
})
const cardConnectionRefs = z.object({
primary_button: z
.object({
linkConnection: linkConnectionRefs,
})
.nullable(),
secondary_button: z
.object({
linkConnection: linkConnectionRefs,
})
.nullable(),
system: z.object({
content_type_uid: z.string(),
uid: z.string(),
}),
})
export const getHeaderRefSchema = z.object({
all_header: z.object({
items: z
.array(
z.object({
top_link: z
.object({
linkConnection: linkConnectionRefs,
})
.nullable(),
menu_items: z.array(
z.object({
linkConnection: linkConnectionRefs,
see_all_link: z.object({
linkConnection: linkConnectionRefs,
}),
cardConnection: z.object({
edges: z
.array(
z.object({
node: cardConnectionRefs,
})
)
.max(1),
}),
submenu: z.array(
z.object({
links: z.array(
z.object({ linkConnection: linkConnectionRefs })
),
})
),
})
),
system: z.object({
content_type_uid: z.string(),
uid: z.string(),
}),
})
)
.length(1),
}),
})

View File

@@ -14,7 +14,11 @@ import { request } from "@/lib/graphql/request"
import { notFound } from "@/server/errors/trpc"
import { contentstackBaseProcedure, router } from "@/server/trpc"
import { generateRefsResponseTag, generateTag } from "@/utils/generateTag"
import {
generateRefsResponseTag,
generateTag,
generateTags,
} from "@/utils/generateTag"
import { langInput } from "./input"
import {
@@ -24,11 +28,13 @@ import {
CurrentHeaderRefDataRaw,
FooterDataRaw,
FooterRefDataRaw,
getHeaderRefSchema,
getHeaderSchema,
validateContactConfigSchema,
validateCurrentHeaderConfigSchema,
validateFooterConfigSchema,
} from "./output"
import { getConnections } from "./utils"
import { HeaderRefResponse, HeaderResponse } from "@/types/header"
@@ -64,13 +70,13 @@ const getCurrentHeaderFailCounter = meter.createCounter(
)
// OpenTelemetry metrics: Header
const getHeaderRefCounter = meter.createCounter(
const getHeaderRefsCounter = meter.createCounter(
"trpc.contentstack.header.ref.get"
)
const getHeaderRefSuccessCounter = meter.createCounter(
const getHeaderRefsSuccessCounter = meter.createCounter(
"trpc.contentstack.header.ref.get-success"
)
const getHeaderRefFailCounter = meter.createCounter(
const getHeaderRefsFailCounter = meter.createCounter(
"trpc.contentstack.header.ref.get-fail"
)
const getHeaderCounter = meter.createCounter("trpc.contentstack.header.get")
@@ -164,31 +170,90 @@ export const baseQueryRouter = router({
}),
header: contentstackBaseProcedure.query(async ({ ctx }) => {
const { lang } = ctx
getHeaderRefCounter.add(1, { lang })
getHeaderRefsCounter.add(1, { lang })
console.info(
"contentstack.header.ref start",
"contentstack.header.refs start",
JSON.stringify({ query: { lang } })
)
// TODO: Add better ref types and error handling for responseRef
const responseRef = await request<HeaderRefResponse>(GetHeaderRef, {
locale: lang,
})
const responseRef = await request<HeaderRefResponse>(
GetHeaderRef,
{
locale: lang,
},
{
cache: "force-cache",
next: {
tags: [generateRefsResponseTag(lang, "header")],
},
}
)
getCurrentHeaderCounter.add(1, { lang })
if (!responseRef.data) {
const notFoundError = notFound(responseRef)
getHeaderRefsFailCounter.add(1, {
lang,
error_type: "not_found",
error: JSON.stringify({ code: notFoundError.code }),
})
console.error(
"contentstack.header.refs not found error",
JSON.stringify({
query: {
lang,
},
error: { code: notFoundError.code },
})
)
throw notFoundError
}
const validatedHeaderRefs = getHeaderRefSchema.safeParse(responseRef.data)
if (!validatedHeaderRefs.success) {
getHeaderRefsFailCounter.add(1, {
lang,
error_type: "validation_error",
error: JSON.stringify(validatedHeaderRefs.error),
})
console.error(
"contentstack.header.refs validation error",
JSON.stringify({
query: {
lang,
},
error: validatedHeaderRefs.error,
})
)
return null
}
getHeaderRefsSuccessCounter.add(1, { lang })
console.info(
"contentstack.header.refs success",
JSON.stringify({ query: { lang } })
)
const connections = getConnections(validatedHeaderRefs.data)
getHeaderCounter.add(1, { lang })
console.info(
"contentstack.header start",
JSON.stringify({ query: { lang } })
)
const tags = [
generateTags(lang, connections),
generateTag(
lang,
validatedHeaderRefs.data.all_header.items[0].system.uid
),
].flat()
const response = await request<HeaderResponse>(
GetHeader,
{ locale: lang }
// {
// tags: [
// generateTag(lang, responseRef.data.all_header.items[0].system.uid),
// ],
// }
{ locale: lang },
{ cache: "force-cache", next: { tags } }
)
if (!response.data) {
@@ -422,161 +487,3 @@ export const baseQueryRouter = router({
return validatedFooterConfig.data.all_current_footer.items[0]
}),
})
const json = {
query: { lang: "en" },
error: {
issues: [
{
code: "invalid_type",
expected: "object",
received: "undefined",
path: ["all_header", "items", 0, "top_link", "link"],
message: "Required",
},
{
code: "invalid_type",
expected: "object",
received: "undefined",
path: ["all_header", "items", 0, "menu_items", 0, "link"],
message: "Required",
},
{
code: "invalid_type",
expected: "object",
received: "undefined",
path: [
"all_header",
"items",
0,
"menu_items",
0,
"submenu",
0,
"links",
0,
"link",
],
message: "Required",
},
{
code: "invalid_type",
expected: "object",
received: "undefined",
path: [
"all_header",
"items",
0,
"menu_items",
0,
"submenu",
0,
"links",
1,
"link",
],
message: "Required",
},
{
code: "invalid_type",
expected: "object",
received: "undefined",
path: [
"all_header",
"items",
0,
"menu_items",
0,
"submenu",
1,
"links",
0,
"link",
],
message: "Required",
},
{
code: "invalid_type",
expected: "object",
received: "undefined",
path: [
"all_header",
"items",
0,
"menu_items",
0,
"see_all_link",
"link",
],
message: "Required",
},
{
code: "invalid_type",
expected: "object",
received: "undefined",
path: ["all_header", "items", 0, "menu_items", 1, "link"],
message: "Required",
},
{
code: "invalid_type",
expected: "object",
received: "undefined",
path: [
"all_header",
"items",
0,
"menu_items",
1,
"see_all_link",
"link",
],
message: "Required",
},
{
code: "invalid_type",
expected: "object",
received: "undefined",
path: ["all_header", "items", 0, "menu_items", 2, "link"],
message: "Required",
},
{
code: "invalid_type",
expected: "object",
received: "undefined",
path: [
"all_header",
"items",
0,
"menu_items",
2,
"see_all_link",
"link",
],
message: "Required",
},
{
code: "invalid_type",
expected: "object",
received: "undefined",
path: ["all_header", "items", 0, "menu_items", 3, "link"],
message: "Required",
},
{
code: "invalid_type",
expected: "object",
received: "undefined",
path: [
"all_header",
"items",
0,
"menu_items",
3,
"see_all_link",
"link",
],
message: "Required",
},
],
name: "ZodError",
},
}

View File

@@ -0,0 +1,40 @@
import { HeaderRefResponse } from "@/types/header"
import { Edges } from "@/types/requests/utils/edges"
import { NodeRefs } from "@/types/requests/utils/refs"
export function getConnections(refs: HeaderRefResponse) {
const connections: Edges<NodeRefs>[] = []
const headerData = refs.all_header.items[0]
const topLink = headerData.top_link
if (topLink) {
connections.push(topLink.linkConnection)
}
headerData.menu_items.forEach(
({ linkConnection, see_all_link, cardConnection, submenu }) => {
const card = cardConnection.edges[0]?.node
connections.push(linkConnection)
if (see_all_link) {
connections.push(see_all_link.linkConnection)
}
if (card) {
if (card.primary_button) {
connections.push(card.primary_button.linkConnection)
}
if (card.secondary_button) {
connections.push(card.secondary_button.linkConnection)
}
}
submenu.forEach(({ links }) => {
links.forEach(({ linkConnection }) => {
connections.push(linkConnection)
})
})
}
)
return connections
}