Merged in chore/add-error-details-for-sentry (pull request #3378)
Include more details when throwing errors for debugging in Sentry * WIP throw errors with more details for debugging in Sentry * Fix throwing response-data * Clearer message when a response fails * Add message to errors * better typings * . * Try to send profileID and membershipNumber to Sentry when we fail to parse the apiResponse * rename notFound -> notFoundError * Merge branch 'master' of bitbucket.org:scandic-swap/web into chore/add-error-details-for-sentry Approved-by: Linus Flood
This commit is contained in:
@@ -9,7 +9,7 @@ import { equalsIgnoreCaseAndAccents } from "@scandic-hotels/common/utils/stringE
|
|||||||
import {
|
import {
|
||||||
gatewayTimeout,
|
gatewayTimeout,
|
||||||
httpStatusByErrorCode,
|
httpStatusByErrorCode,
|
||||||
notFound,
|
notFoundError,
|
||||||
} from "@scandic-hotels/trpc/errors"
|
} from "@scandic-hotels/trpc/errors"
|
||||||
import {
|
import {
|
||||||
isCityLocation,
|
isCityLocation,
|
||||||
@@ -36,7 +36,7 @@ export async function GET(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (!country) {
|
if (!country) {
|
||||||
throw notFound(`Country "${countryParam.toLowerCase()}" not found`)
|
throw notFoundError(`Country "${countryParam.toLowerCase()}" not found`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const caller = await serverClient()
|
const caller = await serverClient()
|
||||||
@@ -55,7 +55,7 @@ export async function GET(
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (!city) {
|
if (!city) {
|
||||||
throw notFound(
|
throw notFoundError(
|
||||||
`City "${cityParam.toLowerCase()}" not found in country "${countryParam.toLowerCase()}"`
|
`City "${cityParam.toLowerCase()}" not found in country "${countryParam.toLowerCase()}"`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -71,7 +71,7 @@ export async function GET(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (hotels.length === 0) {
|
if (hotels.length === 0) {
|
||||||
throw notFound(
|
throw notFoundError(
|
||||||
`No hotels found in city "${cityParam.toLowerCase()}" and country "${countryParam.toLowerCase()}"`
|
`No hotels found in city "${cityParam.toLowerCase()}" and country "${countryParam.toLowerCase()}"`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { equalsIgnoreCaseAndAccents } from "@scandic-hotels/common/utils/stringE
|
|||||||
import {
|
import {
|
||||||
gatewayTimeout,
|
gatewayTimeout,
|
||||||
httpStatusByErrorCode,
|
httpStatusByErrorCode,
|
||||||
notFound,
|
notFoundError,
|
||||||
} from "@scandic-hotels/trpc/errors"
|
} from "@scandic-hotels/trpc/errors"
|
||||||
import {
|
import {
|
||||||
isCityLocation,
|
isCityLocation,
|
||||||
@@ -36,7 +36,7 @@ export async function GET(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (!country) {
|
if (!country) {
|
||||||
throw notFound(`Country "${countryParam.toLowerCase()}" not found`)
|
throw notFoundError(`Country "${countryParam.toLowerCase()}" not found`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const caller = await serverClient()
|
const caller = await serverClient()
|
||||||
@@ -52,7 +52,7 @@ export async function GET(
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (cities.length === 0) {
|
if (cities.length === 0) {
|
||||||
throw notFound(
|
throw notFoundError(
|
||||||
`No cities found in country "${countryParam.toLowerCase()}"`
|
`No cities found in country "${countryParam.toLowerCase()}"`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -71,7 +71,7 @@ export async function GET(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (hotels.length === 0) {
|
if (hotels.length === 0) {
|
||||||
throw notFound(
|
throw notFoundError(
|
||||||
`No hotels found in country "${countryParam.toLowerCase()}"`
|
`No hotels found in country "${countryParam.toLowerCase()}"`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
import * as Sentry from "@sentry/nextjs"
|
import * as Sentry from "@sentry/nextjs"
|
||||||
import { TRPCError } from "@trpc/server"
|
|
||||||
|
import { isCustomCause } from "@scandic-hotels/trpc/errors"
|
||||||
|
|
||||||
import { env } from "./env/server"
|
import { env } from "./env/server"
|
||||||
|
|
||||||
|
import type { TRPCError } from "@trpc/server"
|
||||||
|
|
||||||
export const denyUrls: (string | RegExp)[] = [
|
export const denyUrls: (string | RegExp)[] = [
|
||||||
// Ignore preview urls
|
// Ignore preview urls
|
||||||
/\/.{2}\/preview\//,
|
/\/.{2}\/preview\//,
|
||||||
@@ -26,16 +29,24 @@ async function configureSentry() {
|
|||||||
release: env.RELEASE_TAG || undefined,
|
release: env.RELEASE_TAG || undefined,
|
||||||
beforeSend(event, hint) {
|
beforeSend(event, hint) {
|
||||||
const error = hint.originalException
|
const error = hint.originalException
|
||||||
|
|
||||||
// Don't send TRPCErrors with client error codes
|
// Don't send TRPCErrors with client error codes
|
||||||
if (error instanceof TRPCError) {
|
if (isTRPCError(error)) {
|
||||||
const clientErrorCodes = ["CONFLICT", "NOT_FOUND", "UNAUTHORIZED"]
|
const clientErrorCodes = ["CONFLICT", "NOT_FOUND", "UNAUTHORIZED"]
|
||||||
if (clientErrorCodes.includes(error.code)) {
|
if (clientErrorCodes.includes(error.code)) {
|
||||||
return null // Don't send to Sentry
|
return null // Don't send to Sentry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isCustomCause(error.cause)) {
|
||||||
|
event.contexts = event.contexts || {}
|
||||||
|
event.contexts.errorDetails = { data: error.cause.errorDetails }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return event
|
return event
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isTRPCError(error: unknown): error is TRPCError {
|
||||||
|
return error instanceof Error && error.name === "TRPCError"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,66 +1,88 @@
|
|||||||
import { TRPCError } from "@trpc/server"
|
import { TRPCError } from "@trpc/server"
|
||||||
|
|
||||||
export function gatewayTimeout(cause?: unknown) {
|
import { getResponseBody } from "./utils/getResponseBody"
|
||||||
|
|
||||||
|
type CustomCause = {
|
||||||
|
message: string
|
||||||
|
errorDetails: Record<string, unknown>
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResponseLike = {
|
||||||
|
status: number
|
||||||
|
statusText: string
|
||||||
|
body: string | Record<string, unknown>
|
||||||
|
url?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type TRPCCause = ResponseLike | CustomCause | Error | string
|
||||||
|
|
||||||
|
export function isCustomCause(cause: unknown): cause is CustomCause {
|
||||||
|
return (
|
||||||
|
!!cause &&
|
||||||
|
typeof cause === "object" &&
|
||||||
|
"message" in cause &&
|
||||||
|
"errorDetails" in cause &&
|
||||||
|
(cause as CustomCause).errorDetails !== undefined
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isTRPCError(error: unknown): error is TRPCError {
|
||||||
|
return error instanceof Error && error.name === "TRPCError"
|
||||||
|
}
|
||||||
|
|
||||||
|
export function gatewayTimeout(cause?: TRPCCause, message: string = "") {
|
||||||
return new TRPCError({
|
return new TRPCError({
|
||||||
code: "GATEWAY_TIMEOUT",
|
code: "GATEWAY_TIMEOUT",
|
||||||
message: `Gateway Timeout`,
|
cause: harmonizeCause(cause, message),
|
||||||
cause,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function unauthorizedError(cause?: unknown) {
|
export function unauthorizedError(cause?: TRPCCause, message: string = "") {
|
||||||
return new TRPCError({
|
return new TRPCError({
|
||||||
code: "UNAUTHORIZED",
|
code: "UNAUTHORIZED",
|
||||||
message: `Unauthorized`,
|
cause: harmonizeCause(cause, message),
|
||||||
cause,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function forbiddenError(cause?: unknown) {
|
export function forbiddenError(cause?: TRPCCause, message: string = "") {
|
||||||
return new TRPCError({
|
return new TRPCError({
|
||||||
code: "FORBIDDEN",
|
code: "FORBIDDEN",
|
||||||
message: `Forbidden`,
|
cause: harmonizeCause(cause, message),
|
||||||
cause,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function conflictError(cause?: unknown) {
|
export function conflictError(cause?: TRPCCause, message: string = "") {
|
||||||
return new TRPCError({
|
return new TRPCError({
|
||||||
code: "CONFLICT",
|
code: "CONFLICT",
|
||||||
message: `Conflict`,
|
cause: harmonizeCause(cause, message),
|
||||||
cause,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function badRequestError(cause?: unknown) {
|
export function badRequestError(cause?: TRPCCause, message: string = "") {
|
||||||
return new TRPCError({
|
return new TRPCError({
|
||||||
code: "BAD_REQUEST",
|
code: "BAD_REQUEST",
|
||||||
message: `Bad request`,
|
cause: harmonizeCause(cause, message),
|
||||||
cause,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function notFound(cause?: unknown) {
|
export function notFoundError(cause?: TRPCCause, message: string = "") {
|
||||||
return new TRPCError({
|
return new TRPCError({
|
||||||
code: "NOT_FOUND",
|
code: "NOT_FOUND",
|
||||||
message: `Not found`,
|
cause: harmonizeCause(cause, message),
|
||||||
cause,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function unprocessableContent(cause?: unknown) {
|
export function unprocessableContent(cause?: TRPCCause, message: string = "") {
|
||||||
return new TRPCError({
|
return new TRPCError({
|
||||||
code: "UNPROCESSABLE_CONTENT",
|
code: "UNPROCESSABLE_CONTENT",
|
||||||
message: "Unprocessable content",
|
cause: harmonizeCause(cause, message),
|
||||||
cause,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function internalServerError(cause?: unknown) {
|
export function internalServerError(cause?: TRPCCause, message: string = "") {
|
||||||
return new TRPCError({
|
return new TRPCError({
|
||||||
code: "INTERNAL_SERVER_ERROR",
|
code: "INTERNAL_SERVER_ERROR",
|
||||||
message: `Internal Server Error`,
|
cause: harmonizeCause(cause, message),
|
||||||
cause,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,20 +128,137 @@ export function httpStatusByErrorCode(error: TRPCError) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function serverErrorByStatus(status: number, cause?: unknown) {
|
function errorCodeByHttpStatus(status: number): TRPCError["code"] {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
|
case 400:
|
||||||
|
return "BAD_REQUEST"
|
||||||
case 401:
|
case 401:
|
||||||
return unauthorizedError(cause)
|
return "UNAUTHORIZED"
|
||||||
case 403:
|
case 403:
|
||||||
return forbiddenError(cause)
|
return "FORBIDDEN"
|
||||||
case 404:
|
case 404:
|
||||||
return notFound(cause)
|
return "NOT_FOUND"
|
||||||
case 409:
|
case 409:
|
||||||
return conflictError(cause)
|
return "CONFLICT"
|
||||||
case 422:
|
case 422:
|
||||||
return unprocessableContent(cause)
|
return "UNPROCESSABLE_CONTENT"
|
||||||
|
case 504:
|
||||||
|
return "GATEWAY_TIMEOUT"
|
||||||
case 500:
|
case 500:
|
||||||
default:
|
default:
|
||||||
return internalServerError(cause)
|
return "INTERNAL_SERVER_ERROR"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function serverErrorByStatus(
|
||||||
|
status: number,
|
||||||
|
cause: CustomCause | Error | string
|
||||||
|
): TRPCError
|
||||||
|
export function serverErrorByStatus(
|
||||||
|
status: number,
|
||||||
|
cause: ResponseLike,
|
||||||
|
message: string
|
||||||
|
): TRPCError
|
||||||
|
export function serverErrorByStatus(
|
||||||
|
status: number,
|
||||||
|
cause?: TRPCCause,
|
||||||
|
message?: string
|
||||||
|
) {
|
||||||
|
switch (status) {
|
||||||
|
case 401:
|
||||||
|
return unauthorizedError(cause, message)
|
||||||
|
case 403:
|
||||||
|
return forbiddenError(cause, message)
|
||||||
|
case 404:
|
||||||
|
return notFoundError(cause, message)
|
||||||
|
case 409:
|
||||||
|
return conflictError(cause, message)
|
||||||
|
case 422:
|
||||||
|
return unprocessableContent(cause, message)
|
||||||
|
case 500:
|
||||||
|
return internalServerError(cause, message)
|
||||||
|
case 504:
|
||||||
|
return gatewayTimeout(cause, message)
|
||||||
|
default:
|
||||||
|
return internalServerError(cause, message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function harmonizeCause(
|
||||||
|
cause: TRPCCause | undefined,
|
||||||
|
message: string = ""
|
||||||
|
): CustomCause | Error | undefined {
|
||||||
|
if (!cause) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isResponseLike(cause)) {
|
||||||
|
return {
|
||||||
|
message: message || `HTTP Error ${cause.status}: ${cause.statusText}`,
|
||||||
|
errorDetails: {
|
||||||
|
status: cause.status,
|
||||||
|
statusText: cause.statusText || errorCodeByHttpStatus(cause.status),
|
||||||
|
body: truncate(cause.body, 200), // Avoids issues in Sentry with large bodies
|
||||||
|
url: cause.url,
|
||||||
|
},
|
||||||
|
} satisfies CustomCause
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof cause === "string") {
|
||||||
|
return { message: cause, errorDetails: {} } satisfies CustomCause
|
||||||
|
}
|
||||||
|
|
||||||
|
return cause
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function extractResponseDetails(
|
||||||
|
response: Response
|
||||||
|
): Promise<ResponseLike> {
|
||||||
|
const body = await getResponseBody(response)
|
||||||
|
|
||||||
|
return {
|
||||||
|
status: response.status,
|
||||||
|
statusText: response.statusText,
|
||||||
|
body,
|
||||||
|
url: response.url,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isResponseLike(cause: TRPCCause): cause is ResponseLike {
|
||||||
|
if (typeof cause !== "object" || !cause) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!("status" in cause) || typeof cause.status !== "number") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!("statusText" in cause) || typeof cause.statusText !== "string") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!("body" in cause)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
function truncate(
|
||||||
|
str: string | Record<string, unknown>,
|
||||||
|
maxLength: number
|
||||||
|
): string {
|
||||||
|
if (typeof str !== "string") {
|
||||||
|
str = JSON.stringify(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str.length <= maxLength) {
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
const originalLength = str.length
|
||||||
|
|
||||||
|
return (
|
||||||
|
str.slice(0, maxLength) +
|
||||||
|
`... [truncated, original length: ${originalLength}]`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@@ -31,9 +31,11 @@ export const languageProcedure = baseProcedure.use(async function (opts) {
|
|||||||
if (process.env.NODE_ENV === "development" && !parsedInput.success) {
|
if (process.env.NODE_ENV === "development" && !parsedInput.success) {
|
||||||
throw badRequestError({
|
throw badRequestError({
|
||||||
message: "Missing lang in tRPC context",
|
message: "Missing lang in tRPC context",
|
||||||
|
errorDetails: {
|
||||||
path: opts.path,
|
path: opts.path,
|
||||||
type: opts.type,
|
type: opts.type,
|
||||||
input: opts.input,
|
input: opts.input,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import z from "zod"
|
|||||||
import { createCounter } from "@scandic-hotels/common/telemetry"
|
import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||||
|
|
||||||
import * as api from "../../../api"
|
import * as api from "../../../api"
|
||||||
import { serverErrorByStatus } from "../../../errors"
|
import { extractResponseDetails, serverErrorByStatus } from "../../../errors"
|
||||||
import { safeProtectedServiceProcedure } from "../../../procedures"
|
import { safeProtectedServiceProcedure } from "../../../procedures"
|
||||||
import { toApiLang } from "../../../utils"
|
import { toApiLang } from "../../../utils"
|
||||||
|
|
||||||
@@ -51,7 +51,11 @@ export const validatePartnerPayment = safeProtectedServiceProcedure
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
throw serverErrorByStatus(apiResponse.status, apiResponse)
|
throw serverErrorByStatus(
|
||||||
|
apiResponse.status,
|
||||||
|
await extractResponseDetails(apiResponse),
|
||||||
|
"validatePartnerPayment failed"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
metricsValidateBooking.success()
|
metricsValidateBooking.success()
|
||||||
|
|||||||
@@ -2,7 +2,12 @@ import { createCounter } from "@scandic-hotels/common/telemetry"
|
|||||||
|
|
||||||
import { router } from "../.."
|
import { router } from "../.."
|
||||||
import * as api from "../../api"
|
import * as api from "../../api"
|
||||||
import { badRequestError, serverErrorByStatus } from "../../errors"
|
import {
|
||||||
|
badRequestError,
|
||||||
|
extractResponseDetails,
|
||||||
|
notFoundError,
|
||||||
|
serverErrorByStatus,
|
||||||
|
} from "../../errors"
|
||||||
import { createRefIdPlugin } from "../../plugins/refIdToConfirmationNumber"
|
import { createRefIdPlugin } from "../../plugins/refIdToConfirmationNumber"
|
||||||
import {
|
import {
|
||||||
safeProtectedServiceProcedure,
|
safeProtectedServiceProcedure,
|
||||||
@@ -85,8 +90,10 @@ export const bookingQueryRouter = router({
|
|||||||
hotelId: booking.hotelId,
|
hotelId: booking.hotelId,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
throw notFoundError({
|
||||||
throw serverErrorByStatus(404)
|
message: "Hotel data not found",
|
||||||
|
errorDetails: { hotelId: booking.hotelId },
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
metricsGetBooking.success()
|
metricsGetBooking.success()
|
||||||
@@ -163,7 +170,10 @@ export const bookingQueryRouter = router({
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
throw serverErrorByStatus(404)
|
throw notFoundError({
|
||||||
|
message: "Hotel data not found",
|
||||||
|
errorDetails: { hotelId: booking.hotelId },
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
metricsFindBooking.success()
|
metricsFindBooking.success()
|
||||||
@@ -265,14 +275,22 @@ export const bookingQueryRouter = router({
|
|||||||
|
|
||||||
if (!apiResponse.ok) {
|
if (!apiResponse.ok) {
|
||||||
await metricsGetBookingStatus.httpError(apiResponse)
|
await metricsGetBookingStatus.httpError(apiResponse)
|
||||||
throw serverErrorByStatus(apiResponse.status, apiResponse)
|
throw serverErrorByStatus(
|
||||||
|
apiResponse.status,
|
||||||
|
await extractResponseDetails(apiResponse),
|
||||||
|
"getBookingStatus failed"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const apiJson = await apiResponse.json()
|
const apiJson = await apiResponse.json()
|
||||||
const verifiedData = createBookingSchema.safeParse(apiJson)
|
const verifiedData = createBookingSchema.safeParse(apiJson)
|
||||||
if (!verifiedData.success) {
|
if (!verifiedData.success) {
|
||||||
metricsGetBookingStatus.validationError(verifiedData.error)
|
metricsGetBookingStatus.validationError(verifiedData.error)
|
||||||
throw badRequestError()
|
|
||||||
|
throw badRequestError({
|
||||||
|
message: "Invalid booking data",
|
||||||
|
errorDetails: verifiedData.error.formErrors,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
metricsGetBookingStatus.success()
|
metricsGetBookingStatus.success()
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
import { createCounter } from "@scandic-hotels/common/telemetry"
|
import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||||
|
|
||||||
import * as api from "../../api"
|
import * as api from "../../api"
|
||||||
import { badRequestError, serverErrorByStatus } from "../../errors"
|
import {
|
||||||
|
badRequestError,
|
||||||
|
extractResponseDetails,
|
||||||
|
serverErrorByStatus,
|
||||||
|
} from "../../errors"
|
||||||
import { toApiLang } from "../../utils"
|
import { toApiLang } from "../../utils"
|
||||||
import { createBookingSchema } from "./mutation/create/schema"
|
import { createBookingSchema } from "./mutation/create/schema"
|
||||||
import { bookingConfirmationSchema } from "./output"
|
import { bookingConfirmationSchema } from "./output"
|
||||||
@@ -37,7 +41,11 @@ export async function getBooking(
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
throw serverErrorByStatus(apiResponse.status, apiResponse)
|
throw serverErrorByStatus(
|
||||||
|
apiResponse.status,
|
||||||
|
await extractResponseDetails(apiResponse),
|
||||||
|
"getBooking failed"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const apiJson = await apiResponse.json()
|
const apiJson = await apiResponse.json()
|
||||||
@@ -94,7 +102,11 @@ export async function findBooking(
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
throw serverErrorByStatus(apiResponse.status, apiResponse)
|
throw serverErrorByStatus(
|
||||||
|
apiResponse.status,
|
||||||
|
await extractResponseDetails(apiResponse),
|
||||||
|
"findBooking failed"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const apiJson = await apiResponse.json()
|
const apiJson = await apiResponse.json()
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { createCounter } from "@scandic-hotels/common/telemetry"
|
import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||||
|
|
||||||
import { router } from "../../.."
|
import { router } from "../../.."
|
||||||
import { notFound } from "../../../errors"
|
import { notFoundError } from "../../../errors"
|
||||||
import {
|
import {
|
||||||
GetUsePointsModal,
|
GetUsePointsModal,
|
||||||
GetUsePointsModalRefs,
|
GetUsePointsModalRefs,
|
||||||
@@ -34,18 +34,22 @@ export const usePointsModalQueryRouter = router({
|
|||||||
|
|
||||||
metricsRefs.start()
|
metricsRefs.start()
|
||||||
const refsTag = generateRefsResponseTag(lang, "usepointsmodal")
|
const refsTag = generateRefsResponseTag(lang, "usepointsmodal")
|
||||||
|
|
||||||
|
const variables = { locale: lang }
|
||||||
const refsResponse = await request<UsePointsModalRefsData>(
|
const refsResponse = await request<UsePointsModalRefsData>(
|
||||||
GetUsePointsModalRefs,
|
GetUsePointsModalRefs,
|
||||||
{ locale: lang },
|
variables,
|
||||||
{
|
{
|
||||||
key: refsTag,
|
key: refsTag,
|
||||||
ttl: "max",
|
ttl: "max",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
if (!refsResponse.data) {
|
if (!refsResponse.data) {
|
||||||
const notFoundError = notFound(refsResponse)
|
|
||||||
metricsRefs.noDataError()
|
metricsRefs.noDataError()
|
||||||
throw notFoundError
|
throw notFoundError({
|
||||||
|
message: "GetUsePointsModalRefs returned no data",
|
||||||
|
errorDetails: variables,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedRefsData = usePointsModalRefsSchema.safeParse(
|
const validatedRefsData = usePointsModalRefsSchema.safeParse(
|
||||||
@@ -76,7 +80,7 @@ export const usePointsModalQueryRouter = router({
|
|||||||
|
|
||||||
const response = await request<UsePointsModalData>(
|
const response = await request<UsePointsModalData>(
|
||||||
GetUsePointsModal,
|
GetUsePointsModal,
|
||||||
{ locale: lang },
|
variables,
|
||||||
{
|
{
|
||||||
key: tags,
|
key: tags,
|
||||||
ttl: "max",
|
ttl: "max",
|
||||||
@@ -84,9 +88,11 @@ export const usePointsModalQueryRouter = router({
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (!response.data) {
|
if (!response.data) {
|
||||||
const notFoundError = notFound(response)
|
|
||||||
metrics.noDataError()
|
metrics.noDataError()
|
||||||
throw notFoundError
|
throw notFoundError({
|
||||||
|
message: "GetUsePointsModal returned no data",
|
||||||
|
errorDetails: variables,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedResponse = usePointsModalSchema.safeParse(response.data)
|
const validatedResponse = usePointsModalSchema.safeParse(response.data)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { createCounter } from "@scandic-hotels/common/telemetry"
|
import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||||
|
|
||||||
import { router } from "../../.."
|
import { router } from "../../.."
|
||||||
import { notFound } from "../../../errors"
|
import { notFoundError } from "../../../errors"
|
||||||
import {
|
import {
|
||||||
GetAccountPage,
|
GetAccountPage,
|
||||||
GetAccountPageRefs,
|
GetAccountPageRefs,
|
||||||
@@ -32,12 +32,10 @@ export const accountPageQueryRouter = router({
|
|||||||
const metricsRefs = getAccountPageRefsCounter.init({ lang, uid })
|
const metricsRefs = getAccountPageRefsCounter.init({ lang, uid })
|
||||||
metricsRefs.start()
|
metricsRefs.start()
|
||||||
|
|
||||||
|
const variables = { locale: lang, uid }
|
||||||
const refsResponse = await request<GetAccountPageRefsSchema>(
|
const refsResponse = await request<GetAccountPageRefsSchema>(
|
||||||
GetAccountPageRefs,
|
GetAccountPageRefs,
|
||||||
{
|
variables,
|
||||||
locale: lang,
|
|
||||||
uid,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: generateRefsResponseTag(lang, uid),
|
key: generateRefsResponseTag(lang, uid),
|
||||||
ttl: "max",
|
ttl: "max",
|
||||||
@@ -45,9 +43,11 @@ export const accountPageQueryRouter = router({
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (!refsResponse.data) {
|
if (!refsResponse.data) {
|
||||||
const notFoundError = notFound(refsResponse)
|
|
||||||
metricsRefs.noDataError()
|
metricsRefs.noDataError()
|
||||||
throw notFoundError
|
throw notFoundError({
|
||||||
|
message: "GetAccountPageRefs returned no data",
|
||||||
|
errorDetails: variables,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedAccountPageRefs = accountPageRefsSchema.safeParse(
|
const validatedAccountPageRefs = accountPageRefsSchema.safeParse(
|
||||||
@@ -75,10 +75,7 @@ export const accountPageQueryRouter = router({
|
|||||||
|
|
||||||
const response = await request<GetAccountPageSchema>(
|
const response = await request<GetAccountPageSchema>(
|
||||||
GetAccountPage,
|
GetAccountPage,
|
||||||
{
|
variables,
|
||||||
locale: lang,
|
|
||||||
uid,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: tags,
|
key: tags,
|
||||||
ttl: "max",
|
ttl: "max",
|
||||||
@@ -86,9 +83,12 @@ export const accountPageQueryRouter = router({
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (!response.data) {
|
if (!response.data) {
|
||||||
const notFoundError = notFound(response)
|
|
||||||
metrics.noDataError()
|
metrics.noDataError()
|
||||||
throw notFoundError
|
|
||||||
|
throw notFoundError({
|
||||||
|
message: "GetAccountPage returned no data",
|
||||||
|
errorDetails: variables,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedAccountPage = accountPageSchema.safeParse(response.data)
|
const validatedAccountPage = accountPageSchema.safeParse(response.data)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { cache } from "react"
|
|||||||
import { createCounter } from "@scandic-hotels/common/telemetry"
|
import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||||
|
|
||||||
import { router } from "../../.."
|
import { router } from "../../.."
|
||||||
import { notFound } from "../../../errors"
|
import { notFoundError } from "../../../errors"
|
||||||
import { GetContactConfig } from "../../../graphql/Query/ContactConfig.graphql"
|
import { GetContactConfig } from "../../../graphql/Query/ContactConfig.graphql"
|
||||||
import { GetFooter, GetFooterRef } from "../../../graphql/Query/Footer.graphql"
|
import { GetFooter, GetFooterRef } from "../../../graphql/Query/Footer.graphql"
|
||||||
import { GetHeader, GetHeaderRef } from "../../../graphql/Query/Header.graphql"
|
import { GetHeader, GetHeaderRef } from "../../../graphql/Query/Header.graphql"
|
||||||
@@ -65,12 +65,12 @@ const getContactConfig = cache(async (lang: Lang) => {
|
|||||||
const metricsGetContactConfig = getContactConfigCounter.init({ lang })
|
const metricsGetContactConfig = getContactConfigCounter.init({ lang })
|
||||||
|
|
||||||
metricsGetContactConfig.start()
|
metricsGetContactConfig.start()
|
||||||
|
const variables = {
|
||||||
|
locale: lang,
|
||||||
|
}
|
||||||
const response = await request<ContactConfigData>(
|
const response = await request<ContactConfigData>(
|
||||||
GetContactConfig,
|
GetContactConfig,
|
||||||
{
|
variables,
|
||||||
locale: lang,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: `${lang}:contact`,
|
key: `${lang}:contact`,
|
||||||
ttl: "max",
|
ttl: "max",
|
||||||
@@ -78,9 +78,11 @@ const getContactConfig = cache(async (lang: Lang) => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (!response.data) {
|
if (!response.data) {
|
||||||
const notFoundError = notFound(response)
|
|
||||||
metricsGetContactConfig.noDataError()
|
metricsGetContactConfig.noDataError()
|
||||||
throw notFoundError
|
throw notFoundError({
|
||||||
|
message: "GetContactConfig returned no data",
|
||||||
|
errorDetails: variables,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const verifiedData = validateContactConfigSchema.safeParse(response.data)
|
const verifiedData = validateContactConfigSchema.safeParse(response.data)
|
||||||
@@ -109,21 +111,18 @@ export const baseQueryRouter = router({
|
|||||||
|
|
||||||
metricsGetHeaderRefs.start()
|
metricsGetHeaderRefs.start()
|
||||||
|
|
||||||
const responseRef = await request<GetHeaderRefs>(
|
const variables = { locale: lang }
|
||||||
GetHeaderRef,
|
const responseRef = await request<GetHeaderRefs>(GetHeaderRef, variables, {
|
||||||
{
|
|
||||||
locale: lang,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: generateRefsResponseTag(lang, "header"),
|
key: generateRefsResponseTag(lang, "header"),
|
||||||
ttl: "max",
|
ttl: "max",
|
||||||
}
|
})
|
||||||
)
|
|
||||||
|
|
||||||
if (!responseRef.data) {
|
if (!responseRef.data) {
|
||||||
const notFoundError = notFound(responseRef)
|
|
||||||
metricsGetHeaderRefs.noDataError()
|
metricsGetHeaderRefs.noDataError()
|
||||||
throw notFoundError
|
throw notFoundError({
|
||||||
|
message: "GetHeaderRef returned no data",
|
||||||
|
errorDetails: variables,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedHeaderRefs = headerRefsSchema.safeParse(responseRef.data)
|
const validatedHeaderRefs = headerRefsSchema.safeParse(responseRef.data)
|
||||||
@@ -147,16 +146,17 @@ export const baseQueryRouter = router({
|
|||||||
generateTag(lang, validatedHeaderRefs.data.header.system.uid),
|
generateTag(lang, validatedHeaderRefs.data.header.system.uid),
|
||||||
].flat()
|
].flat()
|
||||||
|
|
||||||
const response = await request<GetHeaderData>(
|
const response = await request<GetHeaderData>(GetHeader, variables, {
|
||||||
GetHeader,
|
key: tags,
|
||||||
{ locale: lang },
|
ttl: "max",
|
||||||
{ key: tags, ttl: "max" }
|
})
|
||||||
)
|
|
||||||
|
|
||||||
if (!response.data) {
|
if (!response.data) {
|
||||||
const notFoundError = notFound(response)
|
|
||||||
metricsGetHeader.noDataError()
|
metricsGetHeader.noDataError()
|
||||||
throw notFoundError
|
throw notFoundError({
|
||||||
|
message: "GetHeader returned no data",
|
||||||
|
errorDetails: variables,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedHeaderConfig = headerSchema.safeParse(response.data)
|
const validatedHeaderConfig = headerSchema.safeParse(response.data)
|
||||||
@@ -182,11 +182,10 @@ export const baseQueryRouter = router({
|
|||||||
|
|
||||||
metricsGetFooterRefs.start()
|
metricsGetFooterRefs.start()
|
||||||
|
|
||||||
|
const variables = { locale: lang }
|
||||||
const responseRef = await request<FooterRefDataRaw>(
|
const responseRef = await request<FooterRefDataRaw>(
|
||||||
GetFooterRef,
|
GetFooterRef,
|
||||||
{
|
variables,
|
||||||
locale: lang,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: generateRefsResponseTag(lang, "footer"),
|
key: generateRefsResponseTag(lang, "footer"),
|
||||||
ttl: "max",
|
ttl: "max",
|
||||||
@@ -194,9 +193,11 @@ export const baseQueryRouter = router({
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (!responseRef.data) {
|
if (!responseRef.data) {
|
||||||
const notFoundError = notFound(responseRef)
|
|
||||||
metricsGetFooterRefs.noDataError()
|
metricsGetFooterRefs.noDataError()
|
||||||
throw notFoundError
|
throw notFoundError({
|
||||||
|
message: "GetFooterRef returned no data",
|
||||||
|
errorDetails: variables,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedFooterRefs = validateFooterRefConfigSchema.safeParse(
|
const validatedFooterRefs = validateFooterRefConfigSchema.safeParse(
|
||||||
@@ -223,21 +224,17 @@ export const baseQueryRouter = router({
|
|||||||
generateTag(lang, footerUID),
|
generateTag(lang, footerUID),
|
||||||
].flat()
|
].flat()
|
||||||
|
|
||||||
const response = await request<FooterDataRaw>(
|
const response = await request<FooterDataRaw>(GetFooter, variables, {
|
||||||
GetFooter,
|
|
||||||
{
|
|
||||||
locale: lang,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: tags,
|
key: tags,
|
||||||
ttl: "max",
|
ttl: "max",
|
||||||
}
|
})
|
||||||
)
|
|
||||||
|
|
||||||
if (!response.data) {
|
if (!response.data) {
|
||||||
const notFoundError = notFound(response)
|
|
||||||
metricsGetFooter.noDataError()
|
metricsGetFooter.noDataError()
|
||||||
throw notFoundError
|
throw notFoundError({
|
||||||
|
message: "GetFooter returned no data",
|
||||||
|
errorDetails: variables,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedFooterConfig = validateFooterConfigSchema.safeParse(
|
const validatedFooterConfig = validateFooterConfigSchema.safeParse(
|
||||||
@@ -269,9 +266,10 @@ export const baseQueryRouter = router({
|
|||||||
|
|
||||||
metricsGetSitewideCampaignBannerRefs.start()
|
metricsGetSitewideCampaignBannerRefs.start()
|
||||||
|
|
||||||
|
const refVariables = { locale: lang }
|
||||||
const responseRef = await request<GetSitewideCampaignBannerRefData>(
|
const responseRef = await request<GetSitewideCampaignBannerRefData>(
|
||||||
GetSitewideCampaignBannerRef,
|
GetSitewideCampaignBannerRef,
|
||||||
{ locale: lang },
|
refVariables,
|
||||||
{
|
{
|
||||||
key: generateRefsResponseTag(lang, "sitewide_campaign_banner"),
|
key: generateRefsResponseTag(lang, "sitewide_campaign_banner"),
|
||||||
ttl: "max",
|
ttl: "max",
|
||||||
@@ -279,9 +277,11 @@ export const baseQueryRouter = router({
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (!responseRef.data) {
|
if (!responseRef.data) {
|
||||||
const notFoundError = notFound(responseRef)
|
|
||||||
metricsGetSitewideCampaignBannerRefs.noDataError()
|
metricsGetSitewideCampaignBannerRefs.noDataError()
|
||||||
throw notFoundError
|
throw notFoundError({
|
||||||
|
message: "GetSitewideCampaignBannerRef returned no data",
|
||||||
|
errorDetails: refVariables,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedSitewideCampaignBannerRef =
|
const validatedSitewideCampaignBannerRef =
|
||||||
@@ -312,17 +312,21 @@ export const baseQueryRouter = router({
|
|||||||
|
|
||||||
metricsGetSitewideCampaignBanner.start()
|
metricsGetSitewideCampaignBanner.start()
|
||||||
|
|
||||||
|
const variables = { locale: lang }
|
||||||
const sitewideCampaignBannerResponse =
|
const sitewideCampaignBannerResponse =
|
||||||
await request<GetSitewideCampaignBannerData>(
|
await request<GetSitewideCampaignBannerData>(
|
||||||
GetSitewideCampaignBanner,
|
GetSitewideCampaignBanner,
|
||||||
{ locale: lang },
|
variables,
|
||||||
{ key: tags, ttl: "max" }
|
{ key: tags, ttl: "max" }
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!sitewideCampaignBannerResponse.data) {
|
if (!sitewideCampaignBannerResponse.data) {
|
||||||
const notFoundError = notFound(sitewideCampaignBannerResponse)
|
|
||||||
metricsGetSitewideCampaignBanner.noDataError()
|
metricsGetSitewideCampaignBanner.noDataError()
|
||||||
throw notFoundError
|
|
||||||
|
throw notFoundError({
|
||||||
|
message: "GetSitewideCampaignBanner returned no data",
|
||||||
|
errorDetails: variables,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedSitewideCampaignBanner =
|
const validatedSitewideCampaignBanner =
|
||||||
@@ -354,11 +358,12 @@ export const baseQueryRouter = router({
|
|||||||
|
|
||||||
metricsGetSiteConfigRefs.start()
|
metricsGetSiteConfigRefs.start()
|
||||||
|
|
||||||
|
const refVariables = {
|
||||||
|
locale: lang,
|
||||||
|
}
|
||||||
const responseRef = await request<GetSiteConfigRefData>(
|
const responseRef = await request<GetSiteConfigRefData>(
|
||||||
GetSiteConfigRef,
|
GetSiteConfigRef,
|
||||||
{
|
refVariables,
|
||||||
locale: lang,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: generateRefsResponseTag(lang, "site_config"),
|
key: generateRefsResponseTag(lang, "site_config"),
|
||||||
ttl: "max",
|
ttl: "max",
|
||||||
@@ -366,9 +371,11 @@ export const baseQueryRouter = router({
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (!responseRef.data) {
|
if (!responseRef.data) {
|
||||||
const notFoundError = notFound(responseRef)
|
|
||||||
metricsGetSiteConfigRefs.noDataError()
|
metricsGetSiteConfigRefs.noDataError()
|
||||||
throw notFoundError
|
throw notFoundError({
|
||||||
|
message: "SiteConfigRefs returned no data",
|
||||||
|
errorDetails: refVariables,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedSiteConfigRef = siteConfigRefSchema.safeParse(
|
const validatedSiteConfigRef = siteConfigRefSchema.safeParse(
|
||||||
@@ -397,24 +404,21 @@ export const baseQueryRouter = router({
|
|||||||
|
|
||||||
metricsGetSiteConfig.start()
|
metricsGetSiteConfig.start()
|
||||||
|
|
||||||
|
const variables = { locale: lang }
|
||||||
const [siteConfigResponse, contactConfig] = await Promise.all([
|
const [siteConfigResponse, contactConfig] = await Promise.all([
|
||||||
request<GetSiteConfigData>(
|
request<GetSiteConfigData>(GetSiteConfig, variables, {
|
||||||
GetSiteConfig,
|
|
||||||
{
|
|
||||||
locale: lang,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: tags,
|
key: tags,
|
||||||
ttl: "max",
|
ttl: "max",
|
||||||
}
|
}),
|
||||||
),
|
|
||||||
getContactConfig(lang),
|
getContactConfig(lang),
|
||||||
])
|
])
|
||||||
|
|
||||||
if (!siteConfigResponse.data) {
|
if (!siteConfigResponse.data) {
|
||||||
const notFoundError = notFound(siteConfigResponse)
|
|
||||||
metricsGetSiteConfig.noDataError()
|
metricsGetSiteConfig.noDataError()
|
||||||
throw notFoundError
|
throw notFoundError({
|
||||||
|
message: "SiteConfig returned no data",
|
||||||
|
errorDetails: variables,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedSiteConfig = siteConfigSchema.safeParse(
|
const validatedSiteConfig = siteConfigSchema.safeParse(
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { createCounter } from "@scandic-hotels/common/telemetry"
|
|||||||
|
|
||||||
import { router } from "../../.."
|
import { router } from "../../.."
|
||||||
import { PageContentTypeEnum } from "../../../enums/contentType"
|
import { PageContentTypeEnum } from "../../../enums/contentType"
|
||||||
import { notFound } from "../../../errors"
|
import { notFoundError } from "../../../errors"
|
||||||
import {
|
import {
|
||||||
GetMyPagesBreadcrumbs,
|
GetMyPagesBreadcrumbs,
|
||||||
GetMyPagesBreadcrumbsRefs,
|
GetMyPagesBreadcrumbsRefs,
|
||||||
@@ -115,19 +115,19 @@ const getBreadcrumbs = cache(async function fetchMemoizedBreadcrumbs<T>(
|
|||||||
|
|
||||||
metricsGetBreadcrumbs.start()
|
metricsGetBreadcrumbs.start()
|
||||||
|
|
||||||
const response = await request<T>(
|
const variables = { locale: lang, uid }
|
||||||
query,
|
const response = await request<T>(query, variables, {
|
||||||
{ locale: lang, uid },
|
|
||||||
{
|
|
||||||
key: tags,
|
key: tags,
|
||||||
ttl: "max",
|
ttl: "max",
|
||||||
}
|
})
|
||||||
)
|
|
||||||
|
|
||||||
if (!response.data) {
|
if (!response.data) {
|
||||||
const notFoundError = notFound(response)
|
|
||||||
metricsGetBreadcrumbs.noDataError()
|
metricsGetBreadcrumbs.noDataError()
|
||||||
throw notFoundError
|
|
||||||
|
throw notFoundError({
|
||||||
|
message: "Breadcrumbs query returned no data",
|
||||||
|
errorDetails: variables,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedBreadcrumbs = breadcrumbsSchema.safeParse(
|
const validatedBreadcrumbs = breadcrumbsSchema.safeParse(
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { createCounter } from "@scandic-hotels/common/telemetry"
|
import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||||
|
|
||||||
import { router } from "../../.."
|
import { router } from "../../.."
|
||||||
import { notFound } from "../../../errors"
|
import { notFoundError } from "../../../errors"
|
||||||
import {
|
import {
|
||||||
GetCampaignOverviewPage,
|
GetCampaignOverviewPage,
|
||||||
GetCampaignOverviewPageRefs,
|
GetCampaignOverviewPageRefs,
|
||||||
@@ -36,9 +36,10 @@ export const campaignOverviewPageQueryRouter = router({
|
|||||||
|
|
||||||
metricsGetCampaignOverviewPageRefs.start()
|
metricsGetCampaignOverviewPageRefs.start()
|
||||||
|
|
||||||
|
const refVariables = { locale: lang, uid }
|
||||||
const refsResponse = await request<GetCampaignOverviewPageRefsData>(
|
const refsResponse = await request<GetCampaignOverviewPageRefsData>(
|
||||||
GetCampaignOverviewPageRefs,
|
GetCampaignOverviewPageRefs,
|
||||||
{ locale: lang, uid },
|
refVariables,
|
||||||
{
|
{
|
||||||
key: generateRefsResponseTag(lang, uid),
|
key: generateRefsResponseTag(lang, uid),
|
||||||
ttl: "max",
|
ttl: "max",
|
||||||
@@ -46,9 +47,12 @@ export const campaignOverviewPageQueryRouter = router({
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (!refsResponse.data) {
|
if (!refsResponse.data) {
|
||||||
const notFoundError = notFound(refsResponse)
|
|
||||||
metricsGetCampaignOverviewPageRefs.noDataError()
|
metricsGetCampaignOverviewPageRefs.noDataError()
|
||||||
throw notFoundError
|
|
||||||
|
throw notFoundError({
|
||||||
|
message: "GetCampaignOverviewPageRefs returned no data",
|
||||||
|
errorDetails: refVariables,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedRefsData = campaignOverviewPageRefsSchema.safeParse(
|
const validatedRefsData = campaignOverviewPageRefsSchema.safeParse(
|
||||||
@@ -75,21 +79,22 @@ export const campaignOverviewPageQueryRouter = router({
|
|||||||
|
|
||||||
metricsGetCampaignOverviewPage.start()
|
metricsGetCampaignOverviewPage.start()
|
||||||
|
|
||||||
|
const variables = { locale: lang, uid }
|
||||||
const response = await request<GetCampaignOverviewPageData>(
|
const response = await request<GetCampaignOverviewPageData>(
|
||||||
GetCampaignOverviewPage,
|
GetCampaignOverviewPage,
|
||||||
{
|
variables,
|
||||||
locale: lang,
|
|
||||||
uid,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: tags,
|
key: tags,
|
||||||
ttl: "max",
|
ttl: "max",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
if (!response.data) {
|
if (!response.data) {
|
||||||
const notFoundError = notFound(response)
|
|
||||||
metricsGetCampaignOverviewPage.noDataError()
|
metricsGetCampaignOverviewPage.noDataError()
|
||||||
throw notFoundError
|
|
||||||
|
throw notFoundError({
|
||||||
|
message: "GetCampaignOverviewPage returned no data",
|
||||||
|
errorDetails: variables,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedResponse = campaignOverviewPageSchema.safeParse(
|
const validatedResponse = campaignOverviewPageSchema.safeParse(
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { createCounter } from "@scandic-hotels/common/telemetry"
|
import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||||
|
|
||||||
import { router } from "../../.."
|
import { router } from "../../.."
|
||||||
import { notFound } from "../../../errors"
|
import { notFoundError } from "../../../errors"
|
||||||
import {
|
import {
|
||||||
GetCampaignPage,
|
GetCampaignPage,
|
||||||
GetCampaignPageRefs,
|
GetCampaignPageRefs,
|
||||||
@@ -32,18 +32,21 @@ export const campaignPageQueryRouter = router({
|
|||||||
|
|
||||||
metricsGetCampaignPageRefs.start()
|
metricsGetCampaignPageRefs.start()
|
||||||
|
|
||||||
|
const refVariables = { locale: lang, uid }
|
||||||
const refsResponse = await request<GetCampaignPageRefsData>(
|
const refsResponse = await request<GetCampaignPageRefsData>(
|
||||||
GetCampaignPageRefs,
|
GetCampaignPageRefs,
|
||||||
{ locale: lang, uid },
|
refVariables,
|
||||||
{
|
{
|
||||||
key: generateRefsResponseTag(lang, uid),
|
key: generateRefsResponseTag(lang, uid),
|
||||||
ttl: "max",
|
ttl: "max",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
if (!refsResponse.data) {
|
if (!refsResponse.data) {
|
||||||
const notFoundError = notFound(refsResponse)
|
|
||||||
metricsGetCampaignPageRefs.noDataError()
|
metricsGetCampaignPageRefs.noDataError()
|
||||||
throw notFoundError
|
throw notFoundError({
|
||||||
|
message: "GetCampaignPageRefs returned no data",
|
||||||
|
errorDetails: refVariables,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedRefsData = campaignPageRefsSchema.safeParse(
|
const validatedRefsData = campaignPageRefsSchema.safeParse(
|
||||||
@@ -68,21 +71,21 @@ export const campaignPageQueryRouter = router({
|
|||||||
|
|
||||||
metricsGetCampaignPage.start()
|
metricsGetCampaignPage.start()
|
||||||
|
|
||||||
|
const variables = { locale: lang, uid }
|
||||||
const response = await request<GetCampaignPageData>(
|
const response = await request<GetCampaignPageData>(
|
||||||
GetCampaignPage,
|
GetCampaignPage,
|
||||||
{
|
variables,
|
||||||
locale: lang,
|
|
||||||
uid,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: tags,
|
key: tags,
|
||||||
ttl: "max",
|
ttl: "max",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
if (!response.data) {
|
if (!response.data) {
|
||||||
const notFoundError = notFound(response)
|
|
||||||
metricsGetCampaignPage.noDataError()
|
metricsGetCampaignPage.noDataError()
|
||||||
throw notFoundError
|
throw notFoundError({
|
||||||
|
message: "GetCampaignPage returned no data",
|
||||||
|
errorDetails: variables,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedResponse = campaignPageSchema.safeParse(response.data)
|
const validatedResponse = campaignPageSchema.safeParse(response.data)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { dt } from "@scandic-hotels/common/dt"
|
import { dt } from "@scandic-hotels/common/dt"
|
||||||
import { createCounter } from "@scandic-hotels/common/telemetry"
|
import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||||
|
|
||||||
import { notFound } from "../../../errors"
|
import { notFoundError } from "../../../errors"
|
||||||
import {
|
import {
|
||||||
GetCampaignPagesByHotelUid,
|
GetCampaignPagesByHotelUid,
|
||||||
GetCampaignPagesByHotelUidRefs,
|
GetCampaignPagesByHotelUidRefs,
|
||||||
@@ -121,13 +121,14 @@ export async function getCampaignPagesByHotelPageUid(
|
|||||||
`${hotelPageUid}-${today}`,
|
`${hotelPageUid}-${today}`,
|
||||||
"hotel_page_campaigns"
|
"hotel_page_campaigns"
|
||||||
)
|
)
|
||||||
const refsResponse = await request<GetCampaignPagesByHotelUidRefsData>(
|
const variables = {
|
||||||
GetCampaignPagesByHotelUidRefs,
|
|
||||||
{
|
|
||||||
locale: lang,
|
locale: lang,
|
||||||
hotelPageUid,
|
hotelPageUid,
|
||||||
today,
|
today,
|
||||||
},
|
}
|
||||||
|
const refsResponse = await request<GetCampaignPagesByHotelUidRefsData>(
|
||||||
|
GetCampaignPagesByHotelUidRefs,
|
||||||
|
variables,
|
||||||
{
|
{
|
||||||
key: refsTag,
|
key: refsTag,
|
||||||
ttl: "1d",
|
ttl: "1d",
|
||||||
@@ -135,9 +136,11 @@ export async function getCampaignPagesByHotelPageUid(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (!refsResponse.data) {
|
if (!refsResponse.data) {
|
||||||
const notFoundError = notFound(refsResponse)
|
|
||||||
metricsGetCampaignPagesByHotelUidRefs.noDataError()
|
metricsGetCampaignPagesByHotelUidRefs.noDataError()
|
||||||
throw notFoundError
|
throw notFoundError({
|
||||||
|
message: "GetCampaignPagesByHotelUidRefs returned no data",
|
||||||
|
errorDetails: variables,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedRefsData = campaignPagesByHotelUidRefsSchema.safeParse(
|
const validatedRefsData = campaignPagesByHotelUidRefsSchema.safeParse(
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { createCounter } from "@scandic-hotels/common/telemetry"
|
import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||||
|
|
||||||
import { notFound } from "../../../errors"
|
import { notFoundError } from "../../../errors"
|
||||||
import { GetCollectionPageRefs } from "../../../graphql/Query/CollectionPage/CollectionPage.graphql"
|
import { GetCollectionPageRefs } from "../../../graphql/Query/CollectionPage/CollectionPage.graphql"
|
||||||
import { request } from "../../../graphql/request"
|
import { request } from "../../../graphql/request"
|
||||||
import {
|
import {
|
||||||
@@ -32,13 +32,13 @@ export async function fetchCollectionPageRefs(lang: Lang, uid: string) {
|
|||||||
metricsGetCollectionPageRefs.start()
|
metricsGetCollectionPageRefs.start()
|
||||||
|
|
||||||
const cacheKey = generateRefsResponseTag(lang, uid)
|
const cacheKey = generateRefsResponseTag(lang, uid)
|
||||||
|
const variables = {
|
||||||
const refsResponse = await request<GetCollectionPageRefsSchema>(
|
|
||||||
GetCollectionPageRefs,
|
|
||||||
{
|
|
||||||
locale: lang,
|
locale: lang,
|
||||||
uid,
|
uid,
|
||||||
},
|
}
|
||||||
|
const refsResponse = await request<GetCollectionPageRefsSchema>(
|
||||||
|
GetCollectionPageRefs,
|
||||||
|
variables,
|
||||||
{
|
{
|
||||||
key: cacheKey,
|
key: cacheKey,
|
||||||
ttl: "max",
|
ttl: "max",
|
||||||
@@ -46,9 +46,11 @@ export async function fetchCollectionPageRefs(lang: Lang, uid: string) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (!refsResponse.data) {
|
if (!refsResponse.data) {
|
||||||
const notFoundError = notFound(refsResponse)
|
|
||||||
metricsGetCollectionPageRefs.noDataError()
|
metricsGetCollectionPageRefs.noDataError()
|
||||||
throw notFoundError
|
throw notFoundError({
|
||||||
|
message: "GetCollectionPageRefs returned no data",
|
||||||
|
errorDetails: variables,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return refsResponse.data
|
return refsResponse.data
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { createCounter } from "@scandic-hotels/common/telemetry"
|
import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||||
|
|
||||||
import { notFound } from "../../../errors"
|
import { notFoundError } from "../../../errors"
|
||||||
import { batchRequest } from "../../../graphql/batchRequest"
|
import { batchRequest } from "../../../graphql/batchRequest"
|
||||||
import {
|
import {
|
||||||
GetContentPageBlocksRefs,
|
GetContentPageBlocksRefs,
|
||||||
@@ -34,10 +34,11 @@ export async function fetchContentPageRefs(lang: Lang, uid: string) {
|
|||||||
|
|
||||||
metricsGetContentPageRefs.start()
|
metricsGetContentPageRefs.start()
|
||||||
|
|
||||||
|
const variables = { locale: lang, uid }
|
||||||
const res = await batchRequest<GetContentPageRefsSchema>([
|
const res = await batchRequest<GetContentPageRefsSchema>([
|
||||||
{
|
{
|
||||||
document: GetContentPageRefs,
|
document: GetContentPageRefs,
|
||||||
variables: { locale: lang, uid },
|
variables,
|
||||||
cacheOptions: {
|
cacheOptions: {
|
||||||
key: generateRefsResponseTag(lang, uid),
|
key: generateRefsResponseTag(lang, uid),
|
||||||
ttl: "max",
|
ttl: "max",
|
||||||
@@ -45,7 +46,7 @@ export async function fetchContentPageRefs(lang: Lang, uid: string) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
document: GetContentPageBlocksRefs,
|
document: GetContentPageBlocksRefs,
|
||||||
variables: { locale: lang, uid },
|
variables,
|
||||||
cacheOptions: {
|
cacheOptions: {
|
||||||
key: generateTag(lang, uid + 1),
|
key: generateTag(lang, uid + 1),
|
||||||
ttl: "max",
|
ttl: "max",
|
||||||
@@ -53,9 +54,11 @@ export async function fetchContentPageRefs(lang: Lang, uid: string) {
|
|||||||
},
|
},
|
||||||
])
|
])
|
||||||
if (!res.data) {
|
if (!res.data) {
|
||||||
const notFoundError = notFound(res)
|
|
||||||
metricsGetContentPageRefs.noDataError()
|
metricsGetContentPageRefs.noDataError()
|
||||||
throw notFoundError
|
throw notFoundError({
|
||||||
|
message: "GetContentPageRefs/GetContentPageBlocksRefs returned no data",
|
||||||
|
errorDetails: variables,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedData = contentPageRefsSchema.safeParse(res.data)
|
const validatedData = contentPageRefsSchema.safeParse(res.data)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { createCounter } from "@scandic-hotels/common/telemetry"
|
import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||||
|
|
||||||
import { router } from "../../.."
|
import { router } from "../../.."
|
||||||
import { notFound } from "../../../errors"
|
import { notFoundError } from "../../../errors"
|
||||||
import {
|
import {
|
||||||
GetDestinationCityPage,
|
GetDestinationCityPage,
|
||||||
GetDestinationCityPageRefs,
|
GetDestinationCityPageRefs,
|
||||||
@@ -34,9 +34,10 @@ export const destinationCityPageQueryRouter = router({
|
|||||||
|
|
||||||
metricsGetDestinationCityPageRefs.start()
|
metricsGetDestinationCityPageRefs.start()
|
||||||
|
|
||||||
|
const variables = { locale: lang, uid }
|
||||||
const refsResponse = await request<GetDestinationCityPageRefsSchema>(
|
const refsResponse = await request<GetDestinationCityPageRefsSchema>(
|
||||||
GetDestinationCityPageRefs,
|
GetDestinationCityPageRefs,
|
||||||
{ locale: lang, uid },
|
variables,
|
||||||
{
|
{
|
||||||
key: generateRefsResponseTag(lang, uid),
|
key: generateRefsResponseTag(lang, uid),
|
||||||
ttl: "max",
|
ttl: "max",
|
||||||
@@ -44,9 +45,11 @@ export const destinationCityPageQueryRouter = router({
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (!refsResponse.data) {
|
if (!refsResponse.data) {
|
||||||
const notFoundError = notFound(refsResponse)
|
|
||||||
metricsGetDestinationCityPageRefs.noDataError()
|
metricsGetDestinationCityPageRefs.noDataError()
|
||||||
throw notFoundError
|
throw notFoundError({
|
||||||
|
message: "GetDestinationCityPageRefs returned no data",
|
||||||
|
errorDetails: variables,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedRefsData = destinationCityPageRefsSchema.safeParse(
|
const validatedRefsData = destinationCityPageRefsSchema.safeParse(
|
||||||
@@ -73,19 +76,19 @@ export const destinationCityPageQueryRouter = router({
|
|||||||
|
|
||||||
const response = await request<GetDestinationCityPageData>(
|
const response = await request<GetDestinationCityPageData>(
|
||||||
GetDestinationCityPage,
|
GetDestinationCityPage,
|
||||||
{
|
variables,
|
||||||
locale: lang,
|
|
||||||
uid,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: tags,
|
key: tags,
|
||||||
ttl: "max",
|
ttl: "max",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
if (!response.data) {
|
if (!response.data) {
|
||||||
const notFoundError = notFound(response)
|
|
||||||
metricsGetDestinationCityPage.noDataError()
|
metricsGetDestinationCityPage.noDataError()
|
||||||
throw notFoundError
|
|
||||||
|
throw notFoundError({
|
||||||
|
message: "GetDestinationCityPage returned no data",
|
||||||
|
errorDetails: variables,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedResponse = destinationCityPageSchema.safeParse(response.data)
|
const validatedResponse = destinationCityPageSchema.safeParse(response.data)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { createCounter } from "@scandic-hotels/common/telemetry"
|
import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||||
|
|
||||||
import { router } from "../../.."
|
import { router } from "../../.."
|
||||||
import { notFound } from "../../../errors"
|
import { notFoundError } from "../../../errors"
|
||||||
import {
|
import {
|
||||||
GetDestinationCountryPage,
|
GetDestinationCountryPage,
|
||||||
GetDestinationCountryPageRefs,
|
GetDestinationCountryPageRefs,
|
||||||
@@ -38,9 +38,10 @@ export const destinationCountryPageQueryRouter = router({
|
|||||||
|
|
||||||
metricsGetDestinationCountryPageRefs.start()
|
metricsGetDestinationCountryPageRefs.start()
|
||||||
|
|
||||||
|
const variables = { locale: lang, uid }
|
||||||
const refsResponse = await request<GetDestinationCountryPageRefsSchema>(
|
const refsResponse = await request<GetDestinationCountryPageRefsSchema>(
|
||||||
GetDestinationCountryPageRefs,
|
GetDestinationCountryPageRefs,
|
||||||
{ locale: lang, uid },
|
variables,
|
||||||
{
|
{
|
||||||
key: generateRefsResponseTag(lang, uid),
|
key: generateRefsResponseTag(lang, uid),
|
||||||
ttl: "max",
|
ttl: "max",
|
||||||
@@ -48,9 +49,11 @@ export const destinationCountryPageQueryRouter = router({
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (!refsResponse.data) {
|
if (!refsResponse.data) {
|
||||||
const notFoundError = notFound(refsResponse)
|
|
||||||
metricsGetDestinationCountryPageRefs.noDataError()
|
metricsGetDestinationCountryPageRefs.noDataError()
|
||||||
throw notFoundError
|
throw notFoundError({
|
||||||
|
message: "GetDestinationCountryPageRefs returned no data",
|
||||||
|
errorDetails: variables,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedRefsData = destinationCountryPageRefsSchema.safeParse(
|
const validatedRefsData = destinationCountryPageRefsSchema.safeParse(
|
||||||
@@ -77,19 +80,18 @@ export const destinationCountryPageQueryRouter = router({
|
|||||||
|
|
||||||
const response = await request<GetDestinationCountryPageData>(
|
const response = await request<GetDestinationCountryPageData>(
|
||||||
GetDestinationCountryPage,
|
GetDestinationCountryPage,
|
||||||
{
|
variables,
|
||||||
locale: lang,
|
|
||||||
uid,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: tags,
|
key: tags,
|
||||||
ttl: "max",
|
ttl: "max",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
if (!response.data) {
|
if (!response.data) {
|
||||||
const notFoundError = notFound(response)
|
|
||||||
metricsGetDestinationCountryPage.noDataError()
|
metricsGetDestinationCountryPage.noDataError()
|
||||||
throw notFoundError
|
throw notFoundError({
|
||||||
|
message: "GetDestinationCountryPage returned no data",
|
||||||
|
errorDetails: variables,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedResponse = destinationCountryPageSchema.safeParse(
|
const validatedResponse = destinationCountryPageSchema.safeParse(
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { createCounter } from "@scandic-hotels/common/telemetry"
|
|||||||
import { safeTry } from "@scandic-hotels/common/utils/safeTry"
|
import { safeTry } from "@scandic-hotels/common/utils/safeTry"
|
||||||
|
|
||||||
import { router } from "../../.."
|
import { router } from "../../.."
|
||||||
import { notFound } from "../../../errors"
|
import { notFoundError } from "../../../errors"
|
||||||
import {
|
import {
|
||||||
GetDestinationOverviewPage,
|
GetDestinationOverviewPage,
|
||||||
GetDestinationOverviewPageRefs,
|
GetDestinationOverviewPageRefs,
|
||||||
@@ -49,21 +49,21 @@ export const destinationOverviewPageQueryRouter = router({
|
|||||||
|
|
||||||
metricsGetDestinationOverviewPageRefs.start()
|
metricsGetDestinationOverviewPageRefs.start()
|
||||||
|
|
||||||
|
const variables = { locale: lang, uid }
|
||||||
const refsResponse = await request<GetDestinationOverviewPageRefsSchema>(
|
const refsResponse = await request<GetDestinationOverviewPageRefsSchema>(
|
||||||
GetDestinationOverviewPageRefs,
|
GetDestinationOverviewPageRefs,
|
||||||
{
|
variables,
|
||||||
locale: lang,
|
|
||||||
uid,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: generateRefsResponseTag(lang, uid),
|
key: generateRefsResponseTag(lang, uid),
|
||||||
ttl: "max",
|
ttl: "max",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
if (!refsResponse.data) {
|
if (!refsResponse.data) {
|
||||||
const notFoundError = notFound(refsResponse)
|
|
||||||
metricsGetDestinationOverviewPageRefs.noDataError()
|
metricsGetDestinationOverviewPageRefs.noDataError()
|
||||||
throw notFoundError
|
throw notFoundError({
|
||||||
|
message: "GetDestinationOverviewPageRefs returned no data",
|
||||||
|
errorDetails: variables,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedRefsData = destinationOverviewPageRefsSchema.safeParse(
|
const validatedRefsData = destinationOverviewPageRefsSchema.safeParse(
|
||||||
@@ -89,19 +89,18 @@ export const destinationOverviewPageQueryRouter = router({
|
|||||||
|
|
||||||
const response = await request<GetDestinationOverviewPageData>(
|
const response = await request<GetDestinationOverviewPageData>(
|
||||||
GetDestinationOverviewPage,
|
GetDestinationOverviewPage,
|
||||||
{
|
variables,
|
||||||
locale: lang,
|
|
||||||
uid,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: generateTag(lang, uid),
|
key: generateTag(lang, uid),
|
||||||
ttl: "max",
|
ttl: "max",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
if (!response.data) {
|
if (!response.data) {
|
||||||
const notFoundError = notFound(response)
|
|
||||||
metricsGetDestinationOverviewPage.noDataError()
|
metricsGetDestinationOverviewPage.noDataError()
|
||||||
throw notFoundError
|
throw notFoundError({
|
||||||
|
message: "GetDestinationOverviewPage returned no data",
|
||||||
|
errorDetails: variables,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const destinationOverviewPage = destinationOverviewPageSchema.safeParse(
|
const destinationOverviewPage = destinationOverviewPageSchema.safeParse(
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { createCounter } from "@scandic-hotels/common/telemetry"
|
import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||||
|
|
||||||
import { router } from "../../.."
|
import { router } from "../../.."
|
||||||
import { notFound } from "../../../errors"
|
import { notFoundError } from "../../../errors"
|
||||||
import { GetHotelPage } from "../../../graphql/Query/HotelPage/HotelPage.graphql"
|
import { GetHotelPage } from "../../../graphql/Query/HotelPage/HotelPage.graphql"
|
||||||
import { request } from "../../../graphql/request"
|
import { request } from "../../../graphql/request"
|
||||||
import { contentstackExtendedProcedureUID } from "../../../procedures"
|
import { contentstackExtendedProcedureUID } from "../../../procedures"
|
||||||
@@ -21,12 +21,10 @@ export const hotelPageQueryRouter = router({
|
|||||||
|
|
||||||
metricsGetHotelPage.start()
|
metricsGetHotelPage.start()
|
||||||
|
|
||||||
|
const variables = { locale: lang, uid }
|
||||||
const hotelPageResponse = await request<GetHotelPageData>(
|
const hotelPageResponse = await request<GetHotelPageData>(
|
||||||
GetHotelPage,
|
GetHotelPage,
|
||||||
{
|
variables,
|
||||||
locale: lang,
|
|
||||||
uid,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: generateTag(lang, uid),
|
key: generateTag(lang, uid),
|
||||||
ttl: "max",
|
ttl: "max",
|
||||||
@@ -34,9 +32,12 @@ export const hotelPageQueryRouter = router({
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (!hotelPageResponse.data) {
|
if (!hotelPageResponse.data) {
|
||||||
const notFoundError = notFound(hotelPageResponse)
|
|
||||||
metricsGetHotelPage.noDataError()
|
metricsGetHotelPage.noDataError()
|
||||||
throw notFoundError
|
|
||||||
|
throw notFoundError({
|
||||||
|
message: "GetHotelPage returned no data",
|
||||||
|
errorDetails: variables,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedHotelPage = hotelPageSchema.safeParse(hotelPageResponse.data)
|
const validatedHotelPage = hotelPageSchema.safeParse(hotelPageResponse.data)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
import { createCounter } from "@scandic-hotels/common/telemetry"
|
import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||||
|
|
||||||
import { router } from "../../.."
|
import { router } from "../../.."
|
||||||
import { notFound } from "../../../errors"
|
import { notFoundError } from "../../../errors"
|
||||||
import {
|
import {
|
||||||
GetAllLoyaltyLevels,
|
GetAllLoyaltyLevels,
|
||||||
GetLoyaltyLevel,
|
GetLoyaltyLevel,
|
||||||
@@ -48,9 +48,12 @@ export const getAllLoyaltyLevels = cache(async (lang: Lang) => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (!loyaltyLevelsConfigResponse.data) {
|
if (!loyaltyLevelsConfigResponse.data) {
|
||||||
const notFoundError = notFound(loyaltyLevelsConfigResponse)
|
|
||||||
metricsGetLoyaltyLevelAll.noDataError()
|
metricsGetLoyaltyLevelAll.noDataError()
|
||||||
throw notFoundError
|
|
||||||
|
throw notFoundError({
|
||||||
|
message: "GetAllLoyaltyLevels returned no data",
|
||||||
|
errorDetails: { lang, level_ids: allLevelIds },
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedLoyaltyLevels = validateLoyaltyLevelsSchema.safeParse(
|
const validatedLoyaltyLevels = validateLoyaltyLevelsSchema.safeParse(
|
||||||
@@ -90,9 +93,11 @@ export const getLoyaltyLevel = cache(
|
|||||||
!loyaltyLevelsConfigResponse.data ||
|
!loyaltyLevelsConfigResponse.data ||
|
||||||
!loyaltyLevelsConfigResponse.data.all_loyalty_level.items.length
|
!loyaltyLevelsConfigResponse.data.all_loyalty_level.items.length
|
||||||
) {
|
) {
|
||||||
const notFoundError = notFound(loyaltyLevelsConfigResponse)
|
|
||||||
metricsGetLoyaltyLevel.noDataError()
|
metricsGetLoyaltyLevel.noDataError()
|
||||||
throw notFoundError
|
throw notFoundError({
|
||||||
|
message: "GetLoyaltyLevel returned no data",
|
||||||
|
errorDetails: { lang, level_id },
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedLoyaltyLevels = validateLoyaltyLevelsSchema.safeParse(
|
const validatedLoyaltyLevels = validateLoyaltyLevelsSchema.safeParse(
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { createCounter } from "@scandic-hotels/common/telemetry"
|
import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||||
|
|
||||||
import { router } from "../../.."
|
import { router } from "../../.."
|
||||||
import { notFound } from "../../../errors"
|
import { notFoundError } from "../../../errors"
|
||||||
import {
|
import {
|
||||||
GetLoyaltyPage,
|
GetLoyaltyPage,
|
||||||
GetLoyaltyPageRefs,
|
GetLoyaltyPageRefs,
|
||||||
@@ -47,9 +47,11 @@ export const loyaltyPageQueryRouter = router({
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (!refsResponse.data) {
|
if (!refsResponse.data) {
|
||||||
const notFoundError = notFound(refsResponse)
|
|
||||||
metricsGetLoyaltyPageRefs.noDataError()
|
metricsGetLoyaltyPageRefs.noDataError()
|
||||||
throw notFoundError
|
throw notFoundError({
|
||||||
|
message: "GetLoyaltyPageRefs returned no data",
|
||||||
|
errorDetails: { ...variables },
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedLoyaltyPageRefs = loyaltyPageRefsSchema.safeParse(
|
const validatedLoyaltyPageRefs = loyaltyPageRefsSchema.safeParse(
|
||||||
@@ -86,9 +88,11 @@ export const loyaltyPageQueryRouter = router({
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (!response.data) {
|
if (!response.data) {
|
||||||
const notFoundError = notFound(response)
|
|
||||||
metricsGetLoyaltyPage.noDataError()
|
metricsGetLoyaltyPage.noDataError()
|
||||||
throw notFoundError
|
throw notFoundError({
|
||||||
|
message: "GetLoyaltyPage returned no data",
|
||||||
|
errorDetails: { lang, uid },
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedLoyaltyPage = loyaltyPageSchema.safeParse(response.data)
|
const validatedLoyaltyPage = loyaltyPageSchema.safeParse(response.data)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { createCounter } from "@scandic-hotels/common/telemetry"
|
|||||||
|
|
||||||
import { router } from "../../.."
|
import { router } from "../../.."
|
||||||
import { PageContentTypeEnum } from "../../../enums/contentType"
|
import { PageContentTypeEnum } from "../../../enums/contentType"
|
||||||
import { notFound } from "../../../errors"
|
import { notFoundError } from "../../../errors"
|
||||||
import { GetAccountPageMetadata } from "../../../graphql/Query/AccountPage/Metadata.graphql"
|
import { GetAccountPageMetadata } from "../../../graphql/Query/AccountPage/Metadata.graphql"
|
||||||
import { GetCampaignOverviewPageMetadata } from "../../../graphql/Query/CampaignOverviewPage/Metadata.graphql"
|
import { GetCampaignOverviewPageMetadata } from "../../../graphql/Query/CampaignOverviewPage/Metadata.graphql"
|
||||||
import { GetCampaignPageMetadata } from "../../../graphql/Query/CampaignPage/Metadata.graphql"
|
import { GetCampaignPageMetadata } from "../../../graphql/Query/CampaignPage/Metadata.graphql"
|
||||||
@@ -51,9 +51,12 @@ const fetchMetadata = cache(async function fetchMemoizedMetadata<T>(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (!response.data) {
|
if (!response.data) {
|
||||||
const notFoundError = notFound(response)
|
|
||||||
metricsGetMetadata.noDataError()
|
metricsGetMetadata.noDataError()
|
||||||
throw notFoundError
|
|
||||||
|
throw notFoundError({
|
||||||
|
message: "GetMetadata returned no data",
|
||||||
|
errorDetails: { lang, uid },
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
metricsGetMetadata.success()
|
metricsGetMetadata.success()
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { cache } from "react"
|
|||||||
import { createCounter } from "@scandic-hotels/common/telemetry"
|
import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||||
|
|
||||||
import { router } from "../../.."
|
import { router } from "../../.."
|
||||||
import { notFound } from "../../../errors"
|
import { notFoundError } from "../../../errors"
|
||||||
import { GetAllSasTierComparison } from "../../../graphql/Query/SASTierComparison.graphql"
|
import { GetAllSasTierComparison } from "../../../graphql/Query/SASTierComparison.graphql"
|
||||||
import { request } from "../../../graphql/request"
|
import { request } from "../../../graphql/request"
|
||||||
import { contentstackBaseProcedure } from "../../../procedures"
|
import { contentstackBaseProcedure } from "../../../procedures"
|
||||||
@@ -36,9 +36,12 @@ export const getSasTierComparison = cache(async (lang: Lang) => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (!sasTierComparisonConfigResponse.data) {
|
if (!sasTierComparisonConfigResponse.data) {
|
||||||
const notFoundError = notFound(sasTierComparisonConfigResponse)
|
|
||||||
metricsGetSasTierComparison.noDataError()
|
metricsGetSasTierComparison.noDataError()
|
||||||
throw notFoundError
|
|
||||||
|
throw notFoundError({
|
||||||
|
message: "GetAllSasTierComparison returned no data",
|
||||||
|
errorDetails: { lang },
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedSasTierComparison = validateSasTierComparisonSchema.safeParse(
|
const validatedSasTierComparison = validateSasTierComparisonSchema.safeParse(
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { createCounter } from "@scandic-hotels/common/telemetry"
|
import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||||
|
|
||||||
import { router } from "../../.."
|
import { router } from "../../.."
|
||||||
import { notFound } from "../../../errors"
|
import { notFoundError } from "../../../errors"
|
||||||
import { GetProfilingConsent } from "../../../graphql/Query/ProfilingConsent.graphql"
|
import { GetProfilingConsent } from "../../../graphql/Query/ProfilingConsent.graphql"
|
||||||
import { request } from "../../../graphql/request"
|
import { request } from "../../../graphql/request"
|
||||||
import { contentstackBaseProcedure } from "../../../procedures"
|
import { contentstackBaseProcedure } from "../../../procedures"
|
||||||
@@ -38,9 +38,11 @@ export const profilingConsentQueryRouter = router({
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
if (!response.data) {
|
if (!response.data) {
|
||||||
const notFoundError = notFound(response)
|
|
||||||
metricsGetProfilingConsent.noDataError()
|
metricsGetProfilingConsent.noDataError()
|
||||||
throw notFoundError
|
throw notFoundError({
|
||||||
|
message: "GetProfilingConsent returned no data",
|
||||||
|
errorDetails: { lang },
|
||||||
|
})
|
||||||
}
|
}
|
||||||
const validatedResponse = profilingConsentSchema.safeParse(response.data)
|
const validatedResponse = profilingConsentSchema.safeParse(response.data)
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { createCounter } from "@scandic-hotels/common/telemetry"
|
import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||||
|
|
||||||
import { router } from "../../.."
|
import { router } from "../../.."
|
||||||
import { notFound } from "../../../errors"
|
import { notFoundError } from "../../../errors"
|
||||||
import {
|
import {
|
||||||
GetPromoCampaignPage,
|
GetPromoCampaignPage,
|
||||||
GetPromoCampaignPageRefs,
|
GetPromoCampaignPageRefs,
|
||||||
@@ -42,9 +42,11 @@ export const promoCampaignPageQueryRouter = router({
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
if (!refsResponse.data) {
|
if (!refsResponse.data) {
|
||||||
const notFoundError = notFound(refsResponse)
|
|
||||||
metricsGetPromoCampaignPageRefs.noDataError()
|
metricsGetPromoCampaignPageRefs.noDataError()
|
||||||
throw notFoundError
|
throw notFoundError({
|
||||||
|
message: "GetPromoCampaignPageRefs returned no data",
|
||||||
|
errorDetails: { lang, uid },
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedRefsData = promoCampaignPageRefsSchema.safeParse(
|
const validatedRefsData = promoCampaignPageRefsSchema.safeParse(
|
||||||
@@ -81,9 +83,11 @@ export const promoCampaignPageQueryRouter = router({
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
if (!response.data) {
|
if (!response.data) {
|
||||||
const notFoundError = notFound(response)
|
|
||||||
metricsGetPromoCampaignPage.noDataError()
|
metricsGetPromoCampaignPage.noDataError()
|
||||||
throw notFoundError
|
throw notFoundError({
|
||||||
|
message: "GetPromoCampaignPage returned no data",
|
||||||
|
errorDetails: { lang, uid },
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedResponse = promoCampaignPageSchema.safeParse(response.data)
|
const validatedResponse = promoCampaignPageSchema.safeParse(response.data)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { createCounter } from "@scandic-hotels/common/telemetry"
|
|||||||
|
|
||||||
import { router } from "../../.."
|
import { router } from "../../.."
|
||||||
import * as api from "../../../api"
|
import * as api from "../../../api"
|
||||||
import { notFound } from "../../../errors"
|
import { notFoundError } from "../../../errors"
|
||||||
import {
|
import {
|
||||||
contentStackBaseWithProtectedProcedure,
|
contentStackBaseWithProtectedProcedure,
|
||||||
contentStackBaseWithServiceProcedure,
|
contentStackBaseWithServiceProcedure,
|
||||||
@@ -92,7 +92,7 @@ export const rewardQueryRouter = router({
|
|||||||
metricsGetContentstackRewardAll.dataError(
|
metricsGetContentstackRewardAll.dataError(
|
||||||
`Failed to matched loyalty level between API and CMS for level ${level}`
|
`Failed to matched loyalty level between API and CMS for level ${level}`
|
||||||
)
|
)
|
||||||
throw notFound()
|
throw notFoundError()
|
||||||
}
|
}
|
||||||
const result: LevelWithRewards = {
|
const result: LevelWithRewards = {
|
||||||
...levelConfig,
|
...levelConfig,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { getCacheClient } from "@scandic-hotels/common/dataCache"
|
|||||||
import { createCounter } from "@scandic-hotels/common/telemetry"
|
import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||||
|
|
||||||
import * as api from "../../../api"
|
import * as api from "../../../api"
|
||||||
import { notFound } from "../../../errors"
|
import { notFoundError } from "../../../errors"
|
||||||
import {
|
import {
|
||||||
GetRewards as GetRewards,
|
GetRewards as GetRewards,
|
||||||
GetRewardsRef as GetRewardsRef,
|
GetRewardsRef as GetRewardsRef,
|
||||||
@@ -109,9 +109,12 @@ export async function getCmsRewards(lang: Lang, rewardIds: string[]) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (!refsResponse.data) {
|
if (!refsResponse.data) {
|
||||||
const notFoundError = notFound(refsResponse)
|
|
||||||
metricsGetContentstackRewardAllRefs.noDataError()
|
metricsGetContentstackRewardAllRefs.noDataError()
|
||||||
throw notFoundError
|
|
||||||
|
throw notFoundError({
|
||||||
|
message: "GetRewardsRef returned no data",
|
||||||
|
errorDetails: { lang, rewardIds },
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedRefsData = rewardRefsSchema.safeParse(refsResponse)
|
const validatedRefsData = rewardRefsSchema.safeParse(refsResponse)
|
||||||
@@ -144,9 +147,12 @@ export async function getCmsRewards(lang: Lang, rewardIds: string[]) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (!cmsRewardsResponse.data) {
|
if (!cmsRewardsResponse.data) {
|
||||||
const notFoundError = notFound(cmsRewardsResponse)
|
|
||||||
metricsGetContentstackRewardAll.noDataError()
|
metricsGetContentstackRewardAll.noDataError()
|
||||||
throw notFoundError
|
|
||||||
|
throw notFoundError({
|
||||||
|
message: "GetRewards not found",
|
||||||
|
errorDetails: { lang, rewardIds },
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedCmsRewards =
|
const validatedCmsRewards =
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { createCounter } from "@scandic-hotels/common/telemetry"
|
import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||||
|
|
||||||
import { router } from "../../.."
|
import { router } from "../../.."
|
||||||
import { notFound } from "../../../errors"
|
import { notFoundError } from "../../../errors"
|
||||||
import {
|
import {
|
||||||
GetStartPage,
|
GetStartPage,
|
||||||
GetStartPageRefs,
|
GetStartPageRefs,
|
||||||
@@ -54,9 +54,11 @@ export const startPageQueryRouter = router({
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
if (!refsResponse.data) {
|
if (!refsResponse.data) {
|
||||||
const notFoundError = notFound(refsResponse)
|
|
||||||
metricsGetStartPageRefs.noDataError()
|
metricsGetStartPageRefs.noDataError()
|
||||||
throw notFoundError
|
throw notFoundError({
|
||||||
|
message: "StartPage refs returned no data",
|
||||||
|
errorDetails: { lang, uid },
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedRefsData = startPageRefsSchema.safeParse(refsResponse.data)
|
const validatedRefsData = startPageRefsSchema.safeParse(refsResponse.data)
|
||||||
@@ -95,9 +97,11 @@ export const startPageQueryRouter = router({
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (!response.data) {
|
if (!response.data) {
|
||||||
const notFoundError = notFound(response)
|
|
||||||
metricsGetStartPage.noDataError()
|
metricsGetStartPage.noDataError()
|
||||||
throw notFoundError
|
throw notFoundError({
|
||||||
|
message: "StartPage not found",
|
||||||
|
errorDetails: { lang, uid },
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const startPage = startPageSchema.safeParse(response.data)
|
const startPage = startPageSchema.safeParse(response.data)
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
import { createCounter } from "@scandic-hotels/common/telemetry"
|
import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||||
|
|
||||||
import * as api from "../../../api"
|
import * as api from "../../../api"
|
||||||
import { badRequestError } from "../../../errors"
|
import {
|
||||||
|
badRequestError,
|
||||||
|
extractResponseDetails,
|
||||||
|
serverErrorByStatus,
|
||||||
|
} from "../../../errors"
|
||||||
import { toApiLang } from "../../../utils"
|
import { toApiLang } from "../../../utils"
|
||||||
import { hotelsAvailabilitySchema } from "../output"
|
import { hotelsAvailabilitySchema } from "../output"
|
||||||
|
|
||||||
@@ -70,9 +74,15 @@ export async function getHotelsAvailabilityByCity({
|
|||||||
},
|
},
|
||||||
params
|
params
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!apiResponse.ok) {
|
if (!apiResponse.ok) {
|
||||||
await metricsGetHotelsAvailabilityByCity.httpError(apiResponse)
|
await metricsGetHotelsAvailabilityByCity.httpError(apiResponse)
|
||||||
throw new Error("Failed to fetch hotels availability by city")
|
|
||||||
|
throw serverErrorByStatus(
|
||||||
|
apiResponse.status,
|
||||||
|
await extractResponseDetails(apiResponse),
|
||||||
|
"getHotelsAvailabilityByCity failed"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const apiJson = await apiResponse.json()
|
const apiJson = await apiResponse.json()
|
||||||
|
|||||||
@@ -77,11 +77,13 @@ describe("getLocationsByCountries", () => {
|
|||||||
it("throws unauthorized on 401 response", async () => {
|
it("throws unauthorized on 401 response", async () => {
|
||||||
mockedGetCacheClient.mockResolvedValueOnce(mockedCacheClient)
|
mockedGetCacheClient.mockResolvedValueOnce(mockedCacheClient)
|
||||||
|
|
||||||
mockedApiGet.mockResolvedValueOnce({
|
mockedApiGet.mockResolvedValueOnce(
|
||||||
ok: false,
|
new Response(JSON.stringify({ data: "Unauthorized" }), {
|
||||||
status: 401,
|
status: 401,
|
||||||
json: async () => ({}),
|
statusText: "Unauthorized",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
})
|
})
|
||||||
|
)
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
getLocationsByCountries({
|
getLocationsByCountries({
|
||||||
@@ -89,7 +91,9 @@ describe("getLocationsByCountries", () => {
|
|||||||
citiesByCountry: null,
|
citiesByCountry: null,
|
||||||
serviceToken: "token",
|
serviceToken: "token",
|
||||||
})
|
})
|
||||||
).rejects.toThrow("Unauthorized")
|
).rejects.toMatchObject({
|
||||||
|
code: "UNAUTHORIZED",
|
||||||
|
})
|
||||||
|
|
||||||
expect(mockedApiGet).toHaveBeenCalled()
|
expect(mockedApiGet).toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
@@ -97,11 +101,13 @@ describe("getLocationsByCountries", () => {
|
|||||||
it("throws forbidden on 403 response", async () => {
|
it("throws forbidden on 403 response", async () => {
|
||||||
mockedGetCacheClient.mockResolvedValueOnce(mockedCacheClient)
|
mockedGetCacheClient.mockResolvedValueOnce(mockedCacheClient)
|
||||||
|
|
||||||
mockedApiGet.mockResolvedValueOnce({
|
mockedApiGet.mockResolvedValueOnce(
|
||||||
ok: false,
|
new Response(JSON.stringify({ data: "Forbidden" }), {
|
||||||
status: 403,
|
status: 403,
|
||||||
json: async () => ({}),
|
statusText: "Forbidden",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
})
|
})
|
||||||
|
)
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
getLocationsByCountries({
|
getLocationsByCountries({
|
||||||
@@ -109,7 +115,9 @@ describe("getLocationsByCountries", () => {
|
|||||||
citiesByCountry: null,
|
citiesByCountry: null,
|
||||||
serviceToken: "token",
|
serviceToken: "token",
|
||||||
})
|
})
|
||||||
).rejects.toThrow("Forbidden")
|
).rejects.toMatchObject({
|
||||||
|
code: "FORBIDDEN",
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it("parses locations and enriches city country and hotel city via getCity", async () => {
|
it("parses locations and enriches city country and hotel city via getCity", async () => {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { getCacheClient } from "@scandic-hotels/common/dataCache"
|
|||||||
import { createLogger } from "@scandic-hotels/common/logger/createLogger"
|
import { createLogger } from "@scandic-hotels/common/logger/createLogger"
|
||||||
|
|
||||||
import * as api from "../../../api"
|
import * as api from "../../../api"
|
||||||
import { serverErrorByStatus } from "../../../errors"
|
import { extractResponseDetails, serverErrorByStatus } from "../../../errors"
|
||||||
import { toApiLang } from "../../../utils"
|
import { toApiLang } from "../../../utils"
|
||||||
import { locationCitySchema } from "../schemas/location/city"
|
import { locationCitySchema } from "../schemas/location/city"
|
||||||
import { locationHotelSchema } from "../schemas/location/hotel"
|
import { locationHotelSchema } from "../schemas/location/hotel"
|
||||||
@@ -60,7 +60,11 @@ export async function getLocationsByCountries({
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (!apiResponse.ok) {
|
if (!apiResponse.ok) {
|
||||||
throw serverErrorByStatus(apiResponse.status, { apiResponse })
|
throw serverErrorByStatus(
|
||||||
|
apiResponse.status,
|
||||||
|
await extractResponseDetails(apiResponse),
|
||||||
|
"getLocationsByCountries failed"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const apiJson = await apiResponse.json()
|
const apiJson = await apiResponse.json()
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { env } from "../../../../env/server"
|
|||||||
import { router } from "../../.."
|
import { router } from "../../.."
|
||||||
import * as api from "../../../api"
|
import * as api from "../../../api"
|
||||||
import { Transactions } from "../../../enums/transactions"
|
import { Transactions } from "../../../enums/transactions"
|
||||||
import { notFound } from "../../../errors"
|
import { notFoundError } from "../../../errors"
|
||||||
import {
|
import {
|
||||||
languageProtectedProcedure,
|
languageProtectedProcedure,
|
||||||
protectedProcedure,
|
protectedProcedure,
|
||||||
@@ -47,7 +47,7 @@ export const userQueryRouter = router({
|
|||||||
.query(async function getUser({ ctx }) {
|
.query(async function getUser({ ctx }) {
|
||||||
const user = await ctx.getScandicUser()
|
const user = await ctx.getScandicUser()
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw notFound()
|
throw notFoundError()
|
||||||
}
|
}
|
||||||
|
|
||||||
return parsedUser(user, !ctx.isMFA)
|
return parsedUser(user, !ctx.isMFA)
|
||||||
@@ -68,7 +68,7 @@ export const userQueryRouter = router({
|
|||||||
getBasic: protectedProcedure.query(async function getBasicUser({ ctx }) {
|
getBasic: protectedProcedure.query(async function getBasicUser({ ctx }) {
|
||||||
const user = await ctx.getScandicBasicUser()
|
const user = await ctx.getScandicBasicUser()
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw notFound()
|
throw notFoundError()
|
||||||
}
|
}
|
||||||
|
|
||||||
return user
|
return user
|
||||||
|
|||||||
@@ -1,10 +1,20 @@
|
|||||||
|
import * as Sentry from "@sentry/nextjs"
|
||||||
|
|
||||||
import { createCounter } from "@scandic-hotels/common/telemetry"
|
import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||||
|
|
||||||
import * as api from "../../../api"
|
import * as api from "../../../api"
|
||||||
import { cache } from "../../../DUPLICATED/cache"
|
import { cache } from "../../../DUPLICATED/cache"
|
||||||
import { serverErrorByStatus, sessionExpiredError } from "../../../errors"
|
import {
|
||||||
|
extractResponseDetails,
|
||||||
|
serverErrorByStatus,
|
||||||
|
sessionExpiredError,
|
||||||
|
} from "../../../errors"
|
||||||
import { getBasicUserSchema } from "../output"
|
import { getBasicUserSchema } from "../output"
|
||||||
|
|
||||||
|
import type z from "zod"
|
||||||
|
|
||||||
|
import type { DeepPartial } from "../../../types/deepPartial"
|
||||||
|
|
||||||
export const getBasicUser = cache(
|
export const getBasicUser = cache(
|
||||||
async ({
|
async ({
|
||||||
token,
|
token,
|
||||||
@@ -30,12 +40,17 @@ export const getBasicUser = cache(
|
|||||||
if (!apiResponse.ok) {
|
if (!apiResponse.ok) {
|
||||||
await metricsGetBasicUser.httpError(apiResponse)
|
await metricsGetBasicUser.httpError(apiResponse)
|
||||||
|
|
||||||
throw serverErrorByStatus(apiResponse.status, apiResponse)
|
throw serverErrorByStatus(
|
||||||
|
apiResponse.status,
|
||||||
|
await extractResponseDetails(apiResponse),
|
||||||
|
"getBasicUser failed"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
const apiJson = await apiResponse.json()
|
const apiJson = await apiResponse.json()
|
||||||
|
|
||||||
const verifiedData = getBasicUserSchema.safeParse(apiJson)
|
const verifiedData = getBasicUserSchema.safeParse(apiJson)
|
||||||
if (!verifiedData.success) {
|
if (!verifiedData.success) {
|
||||||
|
addUserToSentry(apiJson)
|
||||||
metricsGetBasicUser.validationError(verifiedData.error)
|
metricsGetBasicUser.validationError(verifiedData.error)
|
||||||
throw verifiedData.error
|
throw verifiedData.error
|
||||||
}
|
}
|
||||||
@@ -45,3 +60,18 @@ export const getBasicUser = cache(
|
|||||||
return verifiedData.data
|
return verifiedData.data
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
function addUserToSentry(apiJson: unknown) {
|
||||||
|
const typedData = apiJson as DeepPartial<z.input<typeof getBasicUserSchema>>
|
||||||
|
if (
|
||||||
|
typeof typedData?.profileId === "undefined" ||
|
||||||
|
typeof typedData?.membershipNumber === "undefined"
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Sentry.setUser({
|
||||||
|
id: typedData?.profileId,
|
||||||
|
username: typedData?.membershipNumber,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,14 +1,21 @@
|
|||||||
|
import * as Sentry from "@sentry/nextjs"
|
||||||
|
|
||||||
import { createCounter } from "@scandic-hotels/common/telemetry"
|
import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||||
|
|
||||||
import * as api from "../../../api"
|
import * as api from "../../../api"
|
||||||
import { cache } from "../../../DUPLICATED/cache"
|
import { cache } from "../../../DUPLICATED/cache"
|
||||||
import {
|
import {
|
||||||
|
extractResponseDetails,
|
||||||
internalServerError,
|
internalServerError,
|
||||||
serverErrorByStatus,
|
serverErrorByStatus,
|
||||||
sessionExpiredError,
|
sessionExpiredError,
|
||||||
} from "../../../errors"
|
} from "../../../errors"
|
||||||
import { getUserSchema } from "../output"
|
import { getUserSchema } from "../output"
|
||||||
|
|
||||||
|
import type { z } from "zod"
|
||||||
|
|
||||||
|
import type { DeepPartial } from "../../../types/deepPartial"
|
||||||
|
|
||||||
export const getVerifiedUser = cache(
|
export const getVerifiedUser = cache(
|
||||||
async ({
|
async ({
|
||||||
token,
|
token,
|
||||||
@@ -42,7 +49,11 @@ export const getVerifiedUser = cache(
|
|||||||
if (!apiResponse.ok) {
|
if (!apiResponse.ok) {
|
||||||
await metricsGetVerifiedUser.httpError(apiResponse)
|
await metricsGetVerifiedUser.httpError(apiResponse)
|
||||||
|
|
||||||
throw serverErrorByStatus(apiResponse.status, apiResponse)
|
throw serverErrorByStatus(
|
||||||
|
apiResponse.status,
|
||||||
|
await extractResponseDetails(apiResponse),
|
||||||
|
"getVerifiedUser failed"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const apiJson = await apiResponse.json()
|
const apiJson = await apiResponse.json()
|
||||||
@@ -57,13 +68,29 @@ export const getVerifiedUser = cache(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const verifiedData = getUserSchema.safeParse(apiJson)
|
const verifiedData = getUserSchema.safeParse(apiJson)
|
||||||
|
|
||||||
if (!verifiedData.success) {
|
if (!verifiedData.success) {
|
||||||
|
addUserToSentry(apiJson)
|
||||||
metricsGetVerifiedUser.validationError(verifiedData.error)
|
metricsGetVerifiedUser.validationError(verifiedData.error)
|
||||||
throw verifiedData.error
|
throw verifiedData.error
|
||||||
}
|
}
|
||||||
|
|
||||||
metricsGetVerifiedUser.success()
|
metricsGetVerifiedUser.success()
|
||||||
|
|
||||||
return verifiedData.data
|
return verifiedData.data
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
function addUserToSentry(apiJson: unknown) {
|
||||||
|
const typedData = apiJson as DeepPartial<z.input<typeof getUserSchema>>
|
||||||
|
if (
|
||||||
|
typeof typedData.data?.attributes?.profileId === "undefined" ||
|
||||||
|
typeof typedData.data?.attributes?.membershipNumber === "undefined"
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Sentry.setUser({
|
||||||
|
id: typedData?.data?.attributes?.profileId,
|
||||||
|
username: typedData?.data?.attributes?.membershipNumber,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
21
packages/trpc/lib/utils/getResponseBody.ts
Normal file
21
packages/trpc/lib/utils/getResponseBody.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
export async function getResponseBody(
|
||||||
|
response: Response
|
||||||
|
): Promise<string | Record<string, unknown>> {
|
||||||
|
const clone = response.clone()
|
||||||
|
|
||||||
|
const contentType = clone.headers.get("content-type")
|
||||||
|
if (contentType && contentType.indexOf("application/json") !== -1) {
|
||||||
|
try {
|
||||||
|
return await clone.json()
|
||||||
|
} catch {
|
||||||
|
try {
|
||||||
|
return await clone.text()
|
||||||
|
} catch (error) {
|
||||||
|
const message = error instanceof Error ? error.message : String(error)
|
||||||
|
return `Unable to extract body '${message}'`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return await clone.text()
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user