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:
Joakim Jäderberg
2026-01-12 09:01:44 +00:00
parent 575763aaa2
commit 99537b13e8
37 changed files with 641 additions and 293 deletions

View File

@@ -1,7 +1,11 @@
import { createCounter } from "@scandic-hotels/common/telemetry"
import * as api from "../../../api"
import { badRequestError } from "../../../errors"
import {
badRequestError,
extractResponseDetails,
serverErrorByStatus,
} from "../../../errors"
import { toApiLang } from "../../../utils"
import { hotelsAvailabilitySchema } from "../output"
@@ -70,9 +74,15 @@ export async function getHotelsAvailabilityByCity({
},
params
)
if (!apiResponse.ok) {
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()

View File

@@ -77,11 +77,13 @@ describe("getLocationsByCountries", () => {
it("throws unauthorized on 401 response", async () => {
mockedGetCacheClient.mockResolvedValueOnce(mockedCacheClient)
mockedApiGet.mockResolvedValueOnce({
ok: false,
status: 401,
json: async () => ({}),
})
mockedApiGet.mockResolvedValueOnce(
new Response(JSON.stringify({ data: "Unauthorized" }), {
status: 401,
statusText: "Unauthorized",
headers: { "Content-Type": "application/json" },
})
)
await expect(
getLocationsByCountries({
@@ -89,7 +91,9 @@ describe("getLocationsByCountries", () => {
citiesByCountry: null,
serviceToken: "token",
})
).rejects.toThrow("Unauthorized")
).rejects.toMatchObject({
code: "UNAUTHORIZED",
})
expect(mockedApiGet).toHaveBeenCalled()
})
@@ -97,11 +101,13 @@ describe("getLocationsByCountries", () => {
it("throws forbidden on 403 response", async () => {
mockedGetCacheClient.mockResolvedValueOnce(mockedCacheClient)
mockedApiGet.mockResolvedValueOnce({
ok: false,
status: 403,
json: async () => ({}),
})
mockedApiGet.mockResolvedValueOnce(
new Response(JSON.stringify({ data: "Forbidden" }), {
status: 403,
statusText: "Forbidden",
headers: { "Content-Type": "application/json" },
})
)
await expect(
getLocationsByCountries({
@@ -109,7 +115,9 @@ describe("getLocationsByCountries", () => {
citiesByCountry: null,
serviceToken: "token",
})
).rejects.toThrow("Forbidden")
).rejects.toMatchObject({
code: "FORBIDDEN",
})
})
it("parses locations and enriches city country and hotel city via getCity", async () => {

View File

@@ -4,7 +4,7 @@ import { getCacheClient } from "@scandic-hotels/common/dataCache"
import { createLogger } from "@scandic-hotels/common/logger/createLogger"
import * as api from "../../../api"
import { serverErrorByStatus } from "../../../errors"
import { extractResponseDetails, serverErrorByStatus } from "../../../errors"
import { toApiLang } from "../../../utils"
import { locationCitySchema } from "../schemas/location/city"
import { locationHotelSchema } from "../schemas/location/hotel"
@@ -60,7 +60,11 @@ export async function getLocationsByCountries({
)
if (!apiResponse.ok) {
throw serverErrorByStatus(apiResponse.status, { apiResponse })
throw serverErrorByStatus(
apiResponse.status,
await extractResponseDetails(apiResponse),
"getLocationsByCountries failed"
)
}
const apiJson = await apiResponse.json()