Skip to content

Commit 31f8861

Browse files
committed
Merge branch 'release/1.13.0'
2 parents e5b9df3 + f52ec50 commit 31f8861

33 files changed

+3776
-103
lines changed

docs/.vitepress/config.mjs

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -263,20 +263,58 @@ function inertiaSailsGuide() {
263263
return [
264264
{
265265
text: 'Getting started',
266-
collapsible: true,
266+
collapsed: false,
267267
items: [
268268
{ text: 'Introduction', link: '/inertia-sails/' },
269269
{
270270
text: 'What is inertia-sails?',
271271
link: '/inertia-sails/what-is-inertia-sails'
272272
},
273-
{ text: 'Installation', link: '/inertia-sails/installation' }
273+
{ text: 'Installation', link: '/inertia-sails/installation' },
274+
{ text: 'Configuration', link: '/inertia-sails/configuration' },
275+
{ text: 'Basic usage', link: '/inertia-sails/basic-usage' }
274276
]
275277
},
276278
{
277-
text: 'Basic usage',
278-
collapsible: true,
279-
items: [{ text: 'Basic usage', link: '/inertia-sails/basic-usage' }]
279+
text: 'Responses',
280+
collapsed: false,
281+
items: [
282+
{ text: 'Inertia responses', link: '/inertia-sails/responses' },
283+
{ text: 'Redirects', link: '/inertia-sails/redirects' }
284+
]
285+
},
286+
{
287+
text: 'Sharing Data',
288+
collapsed: false,
289+
items: [
290+
{ text: 'Sharing data', link: '/inertia-sails/sharing-data' },
291+
{ text: 'Flash messages', link: '/inertia-sails/flash-messages' },
292+
{ text: 'View data', link: '/inertia-sails/view-data' }
293+
]
294+
},
295+
{
296+
text: 'Props',
297+
collapsed: false,
298+
items: [
299+
{ text: 'Once props', link: '/inertia-sails/once-props' },
300+
{ text: 'Deferred props', link: '/inertia-sails/deferred-props' },
301+
{ text: 'Merge props', link: '/inertia-sails/merge-props' },
302+
{ text: 'Optional props', link: '/inertia-sails/optional-props' },
303+
{ text: 'Always props', link: '/inertia-sails/always-props' }
304+
]
305+
},
306+
{
307+
text: 'Advanced',
308+
collapsed: false,
309+
items: [
310+
{ text: 'Infinite scroll', link: '/inertia-sails/infinite-scroll' },
311+
{
312+
text: 'History encryption',
313+
link: '/inertia-sails/history-encryption'
314+
},
315+
{ text: 'Root view', link: '/inertia-sails/root-view' },
316+
{ text: 'Asset versioning', link: '/inertia-sails/asset-versioning' }
317+
]
280318
}
281319
]
282320
}
@@ -351,7 +389,9 @@ function boringStackGuide() {
351389
items: [
352390
{ text: 'Sharing data', link: 'boring-stack/sharing-data' },
353391
{ text: 'Deferred props', link: 'boring-stack/deferred-props' },
354-
{ text: 'Merging props', link: 'boring-stack/merging-props' }
392+
{ text: 'Merging props', link: 'boring-stack/merging-props' },
393+
{ text: 'Once props', link: 'boring-stack/once-props' },
394+
{ text: 'Infinite scroll', link: 'boring-stack/infinite-scroll' }
355395
]
356396
},
357397
{
@@ -364,7 +404,8 @@ function boringStackGuide() {
364404
{ text: 'Email', link: 'boring-stack/email' },
365405
{ text: 'Session', link: 'boring-stack/session' },
366406
{ text: 'File uploads', link: 'boring-stack/file-uploads' },
367-
{ text: 'Testing', link: 'boring-stack/testing' }
407+
{ text: 'Testing', link: 'boring-stack/testing' },
408+
{ text: 'Error handling', link: 'boring-stack/error-handling' }
368409
]
369410
},
370411
{
@@ -413,7 +454,8 @@ function SailsContentGuide() {
413454
items: [
414455
{ text: 'Content collections', link: 'content/collections' },
415456
{ text: 'Querying collections', link: 'content/querying-collections' },
416-
{ text: 'Configuration', link: 'content/configuration' }
457+
{ text: 'Configuration', link: 'content/configuration' },
458+
{ text: 'Partials', link: 'content/partials' }
417459
]
418460
}
419461
]
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
---
2+
head:
3+
- - meta
4+
- property: 'og:image'
5+
content: https://docs.sailscasts.com/boring-stack-social.png
6+
title: Error handling
7+
titleTemplate: The Boring JavaScript Stack
8+
description: Error handling in The Boring JavaScript Stack
9+
prev:
10+
text: Testing
11+
link: '/boring-stack/testing'
12+
next:
13+
text: Deployment
14+
link: '/boring-stack/deployment'
15+
editLink: true
16+
---
17+
18+
# Error handling
19+
20+
The Boring JavaScript Stack provides built-in error handling that integrates seamlessly with Inertia.js, including a development error modal that shows stack traces without losing your page state.
21+
22+
## The error modal
23+
24+
When a server error occurs during an Inertia request in development, instead of showing a blank error page, The Boring Stack displays a styled error modal with the full stack trace. This lets you debug issues without losing your current page state or form data.
25+
26+
The error modal is automatically enabled in development (`NODE_ENV !== 'production'`) and shows:
27+
28+
- HTTP status code
29+
- Error name and message
30+
- Request method and URL
31+
- Full stack trace with syntax highlighting
32+
33+
In production, errors redirect back to the previous page with a flash message.
34+
35+
## Using the serverError response
36+
37+
Define the `serverError` exit in your action:
38+
39+
```js
40+
module.exports = {
41+
exits: {
42+
success: {
43+
responseType: 'inertia'
44+
},
45+
serverError: {
46+
responseType: 'serverError'
47+
}
48+
},
49+
50+
fn: async function () {
51+
try {
52+
const data = await someRiskyOperation()
53+
return { page: 'dashboard', props: { data } }
54+
} catch (error) {
55+
throw { serverError: error }
56+
}
57+
}
58+
}
59+
```
60+
61+
## Direct usage
62+
63+
You can also call `handleServerError` directly:
64+
65+
```js
66+
module.exports = {
67+
fn: async function () {
68+
try {
69+
await dangerousOperation()
70+
} catch (error) {
71+
return sails.inertia.handleServerError(this.req, this.res, error)
72+
}
73+
}
74+
}
75+
```
76+
77+
## Behavior by environment
78+
79+
| Environment | Inertia Request | Non-Inertia Request |
80+
| ----------- | ------------------------------ | -------------------------------- |
81+
| Development | Error modal with stack trace | HTML error page with stack trace |
82+
| Production | Redirect back with flash error | Generic error page |
83+
84+
## Customizing the error modal
85+
86+
The error modal HTML is generated by the `handleServerError` function. If you need to customize it, you can create your own response handler:
87+
88+
```js
89+
// api/responses/serverError.js
90+
module.exports = function serverError(error) {
91+
const sails = this.req._sails
92+
const isDev = process.env.NODE_ENV !== 'production'
93+
const isInertia = this.req.header('X-Inertia')
94+
95+
if (isInertia && isDev) {
96+
// Your custom error HTML
97+
return this.res.status(500).send(buildCustomErrorHtml(error))
98+
}
99+
100+
// Fall back to default handling
101+
return sails.inertia.handleServerError(this.req, this.res, error)
102+
}
103+
```
104+
105+
## Global error handling
106+
107+
For catching unhandled errors globally, you can use Sails' `config/http.js` middleware:
108+
109+
```js
110+
// config/http.js
111+
module.exports.http = {
112+
middleware: {
113+
order: [
114+
// ... other middleware
115+
'errorHandler'
116+
],
117+
118+
errorHandler: function (err, req, res, next) {
119+
if (req.header('X-Inertia')) {
120+
return sails.inertia.handleServerError(req, res, err)
121+
}
122+
return next(err)
123+
}
124+
}
125+
}
126+
```
127+
128+
## Error handling best practices
129+
130+
1. **Use specific exits**: Define clear exit types for different error scenarios
131+
132+
```js
133+
exits: {
134+
success: { responseType: 'inertia' },
135+
notFound: { responseType: 'notFound' },
136+
badRequest: { responseType: 'badRequest' },
137+
serverError: { responseType: 'serverError' }
138+
}
139+
```
140+
141+
2. **Log errors**: Always log server errors for monitoring
142+
143+
```js
144+
catch (error) {
145+
sails.log.error('Payment processing failed:', error)
146+
throw { serverError: error }
147+
}
148+
```
149+
150+
3. **User-friendly production errors**: Use flash messages for production
151+
152+
```js
153+
catch (error) {
154+
sails.log.error('Operation failed:', error)
155+
sails.inertia.flash('error', 'Something went wrong. Please try again.')
156+
return '/dashboard'
157+
}
158+
```
159+
160+
## Validation errors vs server errors
161+
162+
| Type | Response | Use case |
163+
| ------------- | -------------------------- | ------------------------ |
164+
| `badRequest` | 400 + redirect with errors | Form validation failures |
165+
| `serverError` | 500 + error modal/redirect | Unexpected exceptions |
166+
167+
Use `badRequest` for validation errors (user can fix) and `serverError` for unexpected failures (bugs, external service failures).

0 commit comments

Comments
 (0)