Skip to content

Commit 96259d7

Browse files
committed
Loosen restrictions on resource route
1 parent e23d6cb commit 96259d7

File tree

3 files changed

+43
-13
lines changed

3 files changed

+43
-13
lines changed

.changeset/kind-hats-greet.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
"react-router": patch
3+
---
4+
5+
Stop erroring on resource routes that return raw strings/objects and instead serialize them as `text/plain` or `application/json` responses
6+
7+
- This only applies when accessed as a resource route without the `.data` extension
8+
- When accessed from a Single Fetch `.data` request, they will still be encoded via `turbo-stream`

integration/resource-routes-test.ts

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ test.describe("loader in an app", async () => {
6161
export default () => <div data-testid="redirect-destination">You made it!</div>
6262
`,
6363
"app/routes/defer.tsx": js`
64-
export let loader = () => ({ data: 'whatever' });
64+
export let loader = () => ({ data: Promise.resolve('whatever') });
6565
`,
6666
"app/routes/data[.]json.tsx": js`
6767
export let loader = () => Response.json({ hello: "world" });
@@ -101,6 +101,11 @@ test.describe("loader in an app", async () => {
101101
return { hello: 'world' };
102102
}
103103
`,
104+
"app/routes/return-string.tsx": js`
105+
export let loader = () => {
106+
return 'hello world';
107+
}
108+
`,
104109
"app/routes/throw-object.tsx": js`
105110
export let loader = () => {
106111
throw { but: 'why' };
@@ -207,9 +212,25 @@ test.describe("loader in an app", async () => {
207212
expect(await res.text()).toEqual("Partial");
208213
});
209214

210-
// TODO: This test should work once we bring over the changes from
211-
// https://github.com/remix-run/remix/pull/9349 to the v7 branch
212-
test.skip("should handle objects returned from resource routes", async ({
215+
test("should convert strings returned from resource routes to text responses", async ({
216+
page,
217+
}) => {
218+
let app = new PlaywrightFixture(appFixture, page);
219+
let res = await app.goto("/return-string");
220+
expect(res.status()).toBe(200);
221+
expect(await res.text()).toEqual("hello world");
222+
});
223+
224+
test("should convert non-strings returned from resource routes to JSON responses", async ({
225+
page,
226+
}) => {
227+
let app = new PlaywrightFixture(appFixture, page);
228+
let res = await app.goto("/return-object");
229+
expect(res.status()).toBe(200);
230+
expect(await res.json()).toEqual({ hello: "world" });
231+
});
232+
233+
test("should handle objects returned from resource routes", async ({
213234
page,
214235
}) => {
215236
let app = new PlaywrightFixture(appFixture, page);
@@ -256,10 +277,8 @@ test.describe("loader in an app", async () => {
256277
}) => {
257278
let app = new PlaywrightFixture(appFixture, page);
258279
let res = await app.goto("/defer");
259-
expect(res.status()).toBe(500);
260-
expect(await res.text()).toMatch(
261-
"Error: Expected a Response to be returned from resource route handler"
262-
);
280+
expect(res.status()).toBe(200);
281+
expect(await res.json()).toEqual({ data: {} });
263282
});
264283
});
265284

packages/react-router/lib/server-runtime/server.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -504,12 +504,15 @@ async function handleResourceRequest(
504504
requestContext: loadContext,
505505
});
506506

507-
invariant(
508-
isResponse(response),
509-
"Expected a Response to be returned from resource route handler"
510-
);
507+
if (isResponse(response)) {
508+
return response;
509+
}
511510

512-
return response;
511+
if (typeof response === "string") {
512+
return new Response(response);
513+
}
514+
515+
return Response.json(response);
513516
} catch (error: unknown) {
514517
if (isResponse(error)) {
515518
// Note: Not functionally required but ensures that our response headers

0 commit comments

Comments
 (0)