Skip to content

Commit 6d4e212

Browse files
authored
feat(rsc): add unstable_getRequest (#14758)
1 parent 8b26fa6 commit 6d4e212

File tree

5 files changed

+54
-3
lines changed

5 files changed

+54
-3
lines changed

.changeset/plenty-olives-rush.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"react-router": patch
3+
---
4+
5+
add RSC unstable_getRequest

integration/rsc/rsc-test.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,12 @@ implementations.forEach((implementation) => {
545545
id: "render-route-error-response",
546546
path: "render-route-error-response/:id?",
547547
lazy: () => import("./routes/render-route-error-response/home"),
548-
}
548+
},
549+
{
550+
id: "get-request",
551+
path: "/get-request",
552+
lazy: () => import("./routes/get-request/get-request"),
553+
},
549554
],
550555
},
551556
] satisfies RSCRouteConfig;
@@ -1549,6 +1554,17 @@ implementations.forEach((implementation) => {
15491554
return <p>Oh no D:</p>;
15501555
}
15511556
`,
1557+
1558+
"src/routes/get-request/get-request.tsx": js`
1559+
import { unstable_getRequest as getRequest } from "react-router";
1560+
1561+
export function action() { return null; }
1562+
1563+
export default function GetRequest() {
1564+
const request = getRequest();
1565+
return <p>{request.method}</p>;
1566+
}
1567+
`,
15521568
},
15531569
});
15541570
});
@@ -1892,6 +1908,20 @@ implementations.forEach((implementation) => {
18921908
);
18931909
await expect(page.getByText("400 Oh no! Test")).toBeAttached();
18941910
});
1911+
1912+
test("Supports getRequest in server components", async ({ page }) => {
1913+
await page.goto(`http://localhost:${port}/get-request`);
1914+
await expect(page.getByText("GET")).toBeAttached();
1915+
1916+
const response = await page.request.fetch(
1917+
`http://localhost:${port}/get-request`,
1918+
{
1919+
method: "POST",
1920+
},
1921+
);
1922+
const body = await response.text();
1923+
expect(body).toContain("<p>POST</p>");
1924+
});
18951925
});
18961926

18971927
test.describe("Server Actions", () => {

packages/react-router/index-react-server.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
// RSC APIs
2-
export { matchRSCServerRequest as unstable_matchRSCServerRequest } from "./lib/rsc/server.rsc";
2+
export {
3+
getRequest as unstable_getRequest,
4+
matchRSCServerRequest as unstable_matchRSCServerRequest,
5+
} from "./lib/rsc/server.rsc";
36

47
export type {
58
DecodeActionFunction as unstable_DecodeActionFunction,

packages/react-router/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,8 @@ export {
316316
export { RSCDefaultRootErrorBoundary as UNSAFE_RSCDefaultRootErrorBoundary } from "./lib/rsc/errorBoundaries";
317317

318318
// Re-export of RSC types
319-
import type { matchRSCServerRequest } from "./lib/rsc/server.rsc";
319+
import type { getRequest, matchRSCServerRequest } from "./lib/rsc/server.rsc";
320+
export declare const unstable_getRequest: typeof getRequest;
320321
export declare const unstable_matchRSCServerRequest: typeof matchRSCServerRequest;
321322

322323
export type {

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ const WithHydrateFallbackProps: typeof WithHydrateFallbackPropsType =
7878

7979
type ServerContext = {
8080
redirect?: Response;
81+
request: Request;
8182
runningAction: boolean;
8283
};
8384

@@ -88,6 +89,16 @@ const globalVar = (typeof globalThis !== "undefined" ? globalThis : global) as {
8889
const ServerStorage = (globalVar.___reactRouterServerStorage___ ??=
8990
new AsyncLocalStorage<ServerContext>());
9091

92+
export function getRequest() {
93+
const ctx = ServerStorage.getStore();
94+
95+
if (!ctx)
96+
throw new Error(
97+
"getRequest must be called from within a React Server render context",
98+
);
99+
return ctx.request;
100+
}
101+
91102
export const redirect: typeof baseRedirect = (...args) => {
92103
const response = baseRedirect(...args);
93104

@@ -782,6 +793,7 @@ async function generateRenderResponse(
782793

783794
let actionResult: Promise<unknown> | undefined;
784795
const ctx: ServerContext = {
796+
request,
785797
runningAction: false,
786798
};
787799

0 commit comments

Comments
 (0)