Merged in chore/move-destinations-api-endpoint (pull request #3058)

chore: move /api/destinations/[country]/[?city] -> /api/web/destinations/[country]/[?city]

* chore: move /api/destinations/[country]/[?city] -> /api/web/destinations/[country]/[?city]
This commit is contained in:
Joakim Jäderberg
2025-11-03 13:33:45 +00:00
parent 83822fbc76
commit b8d887f82d
3 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,139 @@
import * as Sentry from "@sentry/nextjs"
import { TRPCError } from "@trpc/server"
import { unstable_noStore as noStore } from "next/cache"
import { NextResponse } from "next/server"
import { Lang } from "@scandic-hotels/common/constants/language"
import { equalsIgnoreCaseAndAccents } from "@scandic-hotels/common/utils/stringEquals"
import {
gatewayTimeout,
httpStatusByErrorCode,
notFound,
} from "@scandic-hotels/trpc/errors"
import { Country } from "@scandic-hotels/trpc/types/country"
import {
isCityLocation,
isHotelLocation,
} from "@scandic-hotels/trpc/types/locations"
import { serverClient } from "@/lib/trpc/server"
import { timeout } from "@/utils/timeout"
import { createDataResponse } from "../createDataResponse"
export const revalidate = 28_800 // 8 hours
export async function GET(
_request: Request,
{ params }: { params: Promise<{ country: string; city: string }> }
) {
try {
const { country: countryParam, city: cityParam } = await params
const country = Object.values(Country).find((c) =>
equalsIgnoreCaseAndAccents(c, countryParam)
)
if (!country) {
throw notFound(`Country "${countryParam.toLowerCase()}" not found`)
}
const caller = await serverClient()
const locations = await Promise.any([
timeout(3_000).then(() => {
throw gatewayTimeout("Fetching locations timed out")
}),
caller.hotel.locations.get({ lang: Lang.en }),
])
const city = locations.filter(isCityLocation).find((c) => {
return (
equalsIgnoreCaseAndAccents(c.name, cityParam) &&
equalsIgnoreCaseAndAccents(c.countryName, countryParam)
)
})
if (!city) {
throw notFound(
`City "${cityParam.toLowerCase()}" not found in country "${countryParam.toLowerCase()}"`
)
}
const hotels = locations
.filter(isHotelLocation)
.filter(
(x) =>
x.isActive &&
x.isPublished &&
equalsIgnoreCaseAndAccents(x.relationships.city.name, cityParam)
)
if (hotels.length === 0) {
throw notFound(
`No hotels found in city "${cityParam.toLowerCase()}" and country "${countryParam.toLowerCase()}"`
)
}
return NextResponse.json(
createDataResponse({ countryParam, cityParam, hotels }),
{
status: 200,
headers: {
"Cache-Control": `public, max-age=${revalidate}, stale-while-revalidate=86400`,
"Netlify-CDN-Cache-Control": `public, max-age=${revalidate}, stale-while-revalidate=86400`,
},
}
)
} catch (error) {
noStore()
const noCacheHeader: HeadersInit = {
"Cache-Control": `no-store, max-age=0`,
}
if (error instanceof TRPCError) {
switch (error.code) {
case "GATEWAY_TIMEOUT":
case "INTERNAL_SERVER_ERROR": {
return NextResponse.json(
{
message: error.cause?.toString() || error.message,
},
{
status: httpStatusByErrorCode(error),
headers: {
...noCacheHeader,
},
}
)
}
case "NOT_FOUND": {
return NextResponse.json(
{
message: error.cause?.toString() || error.message,
},
{
status: 404,
headers: {
"Cache-Control": `public, max-age=${revalidate}, stale-while-revalidate=86400`,
"Netlify-CDN-Cache-Control": `public, max-age=${revalidate}, stale-while-revalidate=86400`,
},
}
)
}
}
}
Sentry.captureException(error)
return NextResponse.json(
{ message: "Internal Server Error" },
{
status: 500,
headers: {
...noCacheHeader,
},
}
)
}
}