Files
web/server/routers/booking/query.ts
Matilda Landström 577a4ca35e Merged in feat/SW-1333-hotel-endpoint (pull request #1206)
Feat(SW-133): Add additionalData endpoint

Approved-by: Erik Tiekstra
Approved-by: Fredrik Thorsson
2025-01-27 11:39:13 +00:00

221 lines
6.6 KiB
TypeScript

import { metrics } from "@opentelemetry/api"
import * as api from "@/lib/api"
import { dt } from "@/lib/dt"
import { badRequestError, serverErrorByStatus } from "@/server/errors/trpc"
import { router, serviceProcedure } from "@/server/trpc"
import { getHotelData } from "../hotels/query"
import { bookingConfirmationInput, getBookingStatusInput } from "./input"
import { bookingConfirmationSchema, createBookingSchema } from "./output"
import { getBookedHotelRoom } from "./utils"
const meter = metrics.getMeter("trpc.booking")
const getBookingConfirmationCounter = meter.createCounter(
"trpc.booking.confirmation"
)
const getBookingConfirmationSuccessCounter = meter.createCounter(
"trpc.booking.confirmation-success"
)
const getBookingConfirmationFailCounter = meter.createCounter(
"trpc.booking.confirmation-fail"
)
const getBookingStatusCounter = meter.createCounter("trpc.booking.status")
const getBookingStatusSuccessCounter = meter.createCounter(
"trpc.booking.status-success"
)
const getBookingStatusFailCounter = meter.createCounter(
"trpc.booking.status-fail"
)
export const bookingQueryRouter = router({
confirmation: serviceProcedure
.input(bookingConfirmationInput)
.query(async function ({ ctx, input: { confirmationNumber } }) {
getBookingConfirmationCounter.add(1, { confirmationNumber })
const apiResponse = await api.get(
api.endpoints.v1.Booking.booking(confirmationNumber),
{
headers: {
Authorization: `Bearer ${ctx.serviceToken}`,
},
}
)
if (!apiResponse.ok) {
const responseMessage = await apiResponse.text()
getBookingConfirmationFailCounter.add(1, {
confirmationNumber,
error_type: "http_error",
error: responseMessage,
})
console.error(
"api.booking.confirmation error",
JSON.stringify({
query: { confirmationNumber },
error: {
status: apiResponse.status,
statusText: apiResponse.statusText,
text: responseMessage,
},
})
)
throw serverErrorByStatus(apiResponse.status, apiResponse)
}
const apiJson = await apiResponse.json()
const booking = bookingConfirmationSchema.safeParse(apiJson)
if (!booking.success) {
getBookingConfirmationFailCounter.add(1, {
confirmationNumber,
error_type: "validation_error",
error: JSON.stringify(booking.error),
})
console.error(
"api.booking.confirmation validation error",
JSON.stringify({
query: { confirmationNumber },
error: booking.error,
})
)
throw badRequestError()
}
const hotelData = await getHotelData(
{ hotelId: booking.data.hotelId, language: ctx.lang },
ctx.serviceToken
)
if (!hotelData) {
getBookingConfirmationFailCounter.add(1, {
confirmationNumber,
hotelId: booking.data.hotelId,
error_type: "http_error",
error: "Couldn`t get hotel",
})
console.error(
"api.booking.confirmation error",
JSON.stringify({
query: { confirmationNumber, hotelId: booking.data.hotelId },
error: {
status: apiResponse.status,
statusText: apiResponse.statusText,
text: "Couldn`t get hotel",
},
})
)
throw serverErrorByStatus(404)
}
getBookingConfirmationSuccessCounter.add(1, { confirmationNumber })
console.info(
"api.booking.confirmation success",
JSON.stringify({
query: { confirmationNumber },
})
)
/**
* Add hotels check in and out times to booking check in and out date
* as that is date only (YYYY-MM-DD)
*/
const checkInTime =
hotelData.data.attributes.hotelFacts.checkin.checkInTime
const [checkInHour, checkInMinute] = checkInTime.split(":")
const checkIn = dt(booking.data.checkInDate)
.set("hour", Number(checkInHour))
.set("minute", Number(checkInMinute))
const checkOutTime =
hotelData.data.attributes.hotelFacts.checkin.checkOutTime
const [checkOutHour, checkOutMinute] = checkOutTime.split(":")
const checkOut = dt(booking.data.checkOutDate)
.set("hour", Number(checkOutHour))
.set("minute", Number(checkOutMinute))
booking.data.checkInDate = checkIn.toDate()
booking.data.checkOutDate = checkOut.toDate()
return {
booking: booking.data,
hotel: {
...hotelData.data.attributes,
included: hotelData.included,
},
room: getBookedHotelRoom(
hotelData.included.rooms,
booking.data.roomTypeCode
),
}
}),
status: serviceProcedure.input(getBookingStatusInput).query(async function ({
ctx,
input,
}) {
const { confirmationNumber } = input
getBookingStatusCounter.add(1, { confirmationNumber })
const apiResponse = await api.get(
api.endpoints.v1.Booking.status(confirmationNumber),
{
headers: {
Authorization: `Bearer ${ctx.serviceToken}`,
},
}
)
if (!apiResponse.ok) {
const responseMessage = await apiResponse.text()
getBookingStatusFailCounter.add(1, {
confirmationNumber,
error_type: "http_error",
error: responseMessage,
})
console.error(
"api.booking.status error",
JSON.stringify({
query: { confirmationNumber },
error: {
status: apiResponse.status,
statusText: apiResponse.statusText,
text: responseMessage,
},
})
)
throw serverErrorByStatus(apiResponse.status, apiResponse)
}
const apiJson = await apiResponse.json()
const verifiedData = createBookingSchema.safeParse(apiJson)
if (!verifiedData.success) {
getBookingStatusFailCounter.add(1, {
confirmationNumber,
error_type: "validation_error",
error: JSON.stringify(verifiedData.error),
})
console.error(
"api.booking.status validation error",
JSON.stringify({
query: { confirmationNumber },
error: verifiedData.error,
})
)
throw badRequestError()
}
getBookingStatusSuccessCounter.add(1, { confirmationNumber })
console.info(
"api.booking.status success",
JSON.stringify({
query: { confirmationNumber },
})
)
return verifiedData.data
}),
})