Skip to content

Commit 132c160

Browse files
docs: clarify Resource Route error patterns (#14518)
1 parent 768919a commit 132c160

File tree

1 file changed

+59
-0
lines changed

1 file changed

+59
-0
lines changed

docs/how-to/resource-routes.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,62 @@ export function action(_: Route.ActionArgs) {
6565
});
6666
}
6767
```
68+
69+
## Return Types
70+
71+
Resource Routes are flexible when it comes to the return type - you can return [`Response`][Response] instances or [`data()`][data] objects. A good general rule of thumb when deciding which type to use is:
72+
73+
- If you're using resource routes intended for external consumption, return `Response` instances
74+
- Keeps the resulting response encoding explicit in your code rather than having to wonder how React Router might convert `data() -> Response` under the hood
75+
- If you're accessing resource routes from [fetchers][fetcher] or [`<Form>`][form] submissions, return `data()`
76+
- Keeps things consistent with the loaders/actions in your UI routes
77+
- Allows you to stream promises down to your UI through `data()`/[`Await`][await]
78+
79+
## Error Handling
80+
81+
Throwing an `Error` from Resource route (or anything other than a `Response`/`data()`) will trigger [`handleError`][handleError] and result in a 500 HTTP Response:
82+
83+
```tsx
84+
export function action() {
85+
let db = await getDb();
86+
if (!db) {
87+
// Fatal error - return a 500 response and trigger `handleError`
88+
throw new Error("Could not connect to DB");
89+
}
90+
// ...
91+
}
92+
```
93+
94+
If a resource route generates a `Response` (via `new Response()` or `data()`), it is considered a successful execution and will not trigger `handleError` because the API has successfully produced a Response for the HTTP request. This applies to thrown responses as well as returned responses with a 4xx/5xx status code. This behavior aligns with `fetch()` which does not return a rejected promise on 4xx/5xx Responses.
95+
96+
```tsx
97+
export function action() {
98+
// Non-fatal error - don't trigger `handleError`:
99+
throw new Response(
100+
{ error: "Unauthorized" },
101+
{ status: 401 },
102+
);
103+
104+
// These 3 are equivalent to the above
105+
return new Response(
106+
{ error: "Unauthorized" },
107+
{ status: 401 },
108+
);
109+
110+
throw data({ error: "Unauthorized" }, { status: 401 });
111+
112+
return data({ error: "Unauthorized" }, { status: 401 });
113+
}
114+
```
115+
116+
### Error Boundaries
117+
118+
[Error Boundaries][error-boundary] are only applicable when a resource route is accessed from a UI, such as from a [`fetcher`][fetcher] call or a [`<Form>`][form] submission. If you `throw` from your resource route in these cases, it will bubble to the nearest `ErrorBoundary` in the UI.
119+
120+
[handleError]: ../api/framework-conventions/entry.server.tsx#handleerror
121+
[data]: ../api/utils/data
122+
[Response]: https://developer.mozilla.org/en-US/docs/Web/API/Response
123+
[fetcher]: ../api/hooks/useFetcher
124+
[form]: ../api/components/Form
125+
[await]: ../api/components/Await
126+
[error-boundary]: ../start/framework/route-module#errorboundary

0 commit comments

Comments
 (0)