Skip to content

Commit 13315a1

Browse files
authored
fix(hydra): gracefully handle 2xx responses with non-JSON-LD content type (#165)
Instead of checking for specific status codes (202, 204), ignore any 2xx response whose Content-Type is not application/ld+json or application/problem+json. This fixes errors when API operations (e.g. Symfony Messenger) return 202 Accepted with an empty or non-JSON-LD body. Closes api-platform/admin#156
1 parent e9a7b7e commit 13315a1

File tree

2 files changed

+73
-8
lines changed

2 files changed

+73
-8
lines changed

src/hydra/fetchJsonLd.test.ts

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ test("fetch a JSON-LD document", async () => {
3131
expect(data.body["name"]).toBe("John Lennon");
3232
});
3333

34-
test("fetch a non JSON-LD document", async () => {
34+
test("fetch a non JSON-LD document with 2xx returns empty response", async () => {
3535
server.use(
3636
http.get(
3737
"http://localhost/foo.jsonld",
@@ -44,12 +44,72 @@ test("fetch a non JSON-LD document", async () => {
4444
),
4545
);
4646

47+
const data = await fetchJsonLd("http://localhost/foo.jsonld");
48+
expect(data.response.ok).toBe(true);
49+
expect(data).not.toHaveProperty("body");
50+
});
51+
52+
test("fetch a non JSON-LD document with non-2xx rejects", async () => {
53+
server.use(
54+
http.get(
55+
"http://localhost/foo.jsonld",
56+
() =>
57+
new Response(`<body>Not Found</body>`, {
58+
headers: { "Content-Type": "text/html" },
59+
status: 404,
60+
statusText: "Not Found",
61+
}),
62+
),
63+
);
64+
4765
const promise = fetchJsonLd("http://localhost/foo.jsonld");
4866

49-
await expect(promise).rejects.toHaveProperty("response.ok", true);
67+
await expect(promise).rejects.toHaveProperty("response.ok", false);
5068
await expect(promise).rejects.not.toHaveProperty("body");
5169
});
5270

71+
test("fetch a 202 Accepted with non JSON-LD content type returns empty response", async () => {
72+
server.use(
73+
http.post(
74+
"http://localhost/foo.jsonld",
75+
() =>
76+
new Response(null, {
77+
status: 202,
78+
statusText: "Accepted",
79+
}),
80+
),
81+
);
82+
83+
const data = await fetchJsonLd("http://localhost/foo.jsonld", {
84+
method: "POST",
85+
});
86+
expect(data.response.ok).toBe(true);
87+
expect(data.response.status).toBe(202);
88+
expect(data).not.toHaveProperty("body");
89+
});
90+
91+
test("fetch a 202 Accepted with JSON-LD content type parses body", async () => {
92+
server.use(
93+
http.post("http://localhost/foo.jsonld", () =>
94+
Response.json(httpResponse, {
95+
headers: { "Content-Type": "application/ld+json" },
96+
status: 202,
97+
statusText: "Accepted",
98+
}),
99+
),
100+
);
101+
102+
const data = await fetchJsonLd("http://localhost/foo.jsonld", {
103+
method: "POST",
104+
});
105+
expect(data.response.ok).toBe(true);
106+
expect(data.response.status).toBe(202);
107+
assert("body" in data, "Response should have a body property");
108+
assert(data.body !== null, "Body should not be null");
109+
assert("name" in data.body, "Body should have a name property");
110+
expect(data.body["name"]).toBe("John Lennon");
111+
});
112+
53113
test("fetch an error with Content-Type application/ld+json", async () => {
54114
server.use(
55115
http.get("http://localhost/foo.jsonld", () =>

src/hydra/fetchJsonLd.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,22 @@ export default async function fetchJsonLd(
3535
return { response };
3636
}
3737

38-
if (
39-
status >= 500 ||
40-
!contentType ||
41-
(!contentType.includes(jsonLdMimeType) &&
42-
!contentType.includes(jsonProblemMimeType))
43-
) {
38+
const isJsonContent =
39+
contentType !== null &&
40+
(contentType.includes(jsonLdMimeType) ||
41+
contentType.includes(jsonProblemMimeType));
42+
43+
if (status >= 500 || (!isJsonContent && !response.ok)) {
4444
const reason: RejectedResponseDocument = { response };
4545
// oxlint-disable-next-line no-throw-literal
4646
throw reason;
4747
}
4848

49+
// 2xx response with a content type different from JSON-LD: return empty response
50+
if (!isJsonContent) {
51+
return { response };
52+
}
53+
4954
const body = (await response.json()) as JsonLd;
5055
return {
5156
response,

0 commit comments

Comments
 (0)