Files
web/packages/trpc/lib/routers/hotels/services/getHotelsAvailabilityByHotelIds.ts
Joakim Jäderberg 8b94540d19 Merged in chore/redirect-counter (pull request #3302)
Counter name is now searchable and add counter for redirects

* refactor: createCounter() only takes one argument, the name of the counter. Makes it easier to search for

* feat: add counter when we do a redirect from redirect-service


Approved-by: Linus Flood
2025-12-08 10:24:05 +00:00

127 lines
3.5 KiB
TypeScript

import { getCacheClient } from "@scandic-hotels/common/dataCache"
import { createCounter } from "@scandic-hotels/common/telemetry"
import { env } from "../../../../env/server"
import * as api from "../../../api"
import { badRequestError } from "../../../errors"
import { toApiLang } from "../../../utils"
import { hotelsAvailabilitySchema } from "../output"
import type { Lang } from "@scandic-hotels/common/constants/language"
import type { HotelsByHotelIdsAvailabilityInputSchema } from "../availability/hotelsByHotelIds"
export async function getHotelsAvailabilityByHotelIds({
input,
lang,
userToken,
serviceToken,
userPoints = 0,
}: {
input: HotelsByHotelIdsAvailabilityInputSchema
lang: Lang
userToken: string | null | undefined
serviceToken: string
userPoints: number | undefined
}) {
const {
hotelIds,
roomStayStartDate,
roomStayEndDate,
adults,
children,
bookingCode,
redemption,
} = input
const apiLang = toApiLang(lang)
const params = new URLSearchParams([
["roomStayStartDate", roomStayStartDate],
["roomStayEndDate", roomStayEndDate],
["adults", adults.toString()],
["children", children ?? ""],
["bookingCode", bookingCode],
["isRedemption", redemption.toString()],
["language", apiLang],
])
const getHotelsAvailabilityByHotelIdsCounter = createCounter(
"hotel.getHotelsAvailabilityByHotelIds"
)
const metricsGetHotelsAvailabilityByHotelIds =
getHotelsAvailabilityByHotelIdsCounter.init({
apiLang,
hotelIds,
roomStayStartDate,
roomStayEndDate,
adults,
children,
bookingCode,
redemption,
})
metricsGetHotelsAvailabilityByHotelIds.start()
const cacheClient = await getCacheClient()
const result = cacheClient.cacheOrGet(
`${apiLang}:hotels:availability:${hotelIds.join(",")}:${roomStayStartDate}:${roomStayEndDate}:${adults}:${children}:${bookingCode}`,
async () => {
/**
* Since API expects the params appended and not just
* a comma separated string we need to initialize the
* SearchParams with a sequence of pairs
* (hotelIds=810&hotelIds=879&hotelIds=222 etc.)
**/
hotelIds.forEach((hotelId) =>
params.append("hotelIds", hotelId.toString())
)
const apiResponse = await api.get(
api.endpoints.v1.Availability.hotels(),
{
headers: {
Authorization: `Bearer ${userToken ?? serviceToken}`,
},
},
params
)
if (!apiResponse.ok) {
await metricsGetHotelsAvailabilityByHotelIds.httpError(apiResponse)
throw new Error("Failed to fetch hotels availability by hotelIds")
}
const apiJson = await apiResponse.json()
const validateAvailabilityData =
hotelsAvailabilitySchema.safeParse(apiJson)
if (!validateAvailabilityData.success) {
metricsGetHotelsAvailabilityByHotelIds.validationError(
validateAvailabilityData.error
)
throw badRequestError()
}
if (redemption) {
validateAvailabilityData.data.data.forEach((data) => {
data.attributes.productType?.redemptions?.forEach((r) => {
r.hasEnoughPoints = userPoints >= r.localPrice.pointsPerStay
})
})
}
return {
availability: validateAvailabilityData.data.data.flatMap(
(hotels) => hotels.attributes
),
}
},
redemption ? "no cache" : env.CACHE_TIME_CITY_SEARCH
)
metricsGetHotelsAvailabilityByHotelIds.success()
return result
}