Skip to content

Commit 3b98005

Browse files
authored
[breaking] rename invalid(...) and ValidationError (#8012)
* rename invalid() and ValidationError - closes #7982 * help people migrate
1 parent ef8915f commit 3b98005

File tree

15 files changed

+55
-45
lines changed

15 files changed

+55
-45
lines changed

.changeset/loud-phones-chew.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sveltejs/kit': patch
3+
---
4+
5+
[breaking] rename invalid() to fail() and ValidationError to ActionFailure

documentation/docs/20-core-concepts/30-form-actions.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,12 @@ export const actions = {
140140

141141
### Validation errors
142142

143-
If the request couldn't be processed because of invalid data, you can return validation errors — along with the previously submitted form values — back to the user so that they can try again. The `invalid` function lets you return an HTTP status code (typically 400 or 422, in the case of validation errors) along with the data. The status code is available through `$page.status` and the data through `form`:
143+
If the request couldn't be processed because of invalid data, you can return validation errors — along with the previously submitted form values — back to the user so that they can try again. The `fail` function lets you return an HTTP status code (typically 400 or 422, in the case of validation errors) along with the data. The status code is available through `$page.status` and the data through `form`:
144144

145145
```diff
146146
// @errors: 2339 2304
147147
/// file: src/routes/login/+page.server.js
148-
+import { invalid } from '@sveltejs/kit';
148+
+import { fail } from '@sveltejs/kit';
149149

150150
/** @type {import('./$types').Actions} */
151151
export const actions = {
@@ -155,13 +155,13 @@ export const actions = {
155155
const password = data.get('password');
156156

157157
+ if (!email) {
158-
+ return invalid(400, { email, missing: true });
158+
+ return fail(400, { email, missing: true });
159159
+ }
160160

161161
const user = await db.getUser(email);
162162

163163
+ if (!user || user.password !== hash(password)) {
164-
+ return invalid(400, { email, incorrect: true });
164+
+ return fail(400, { email, incorrect: true });
165165
+ }
166166

167167
cookies.set('sessionid', await db.createSession(user));
@@ -199,7 +199,7 @@ Redirects (and errors) work exactly the same as in [`load`](/docs/load#redirects
199199
```diff
200200
// @errors: 2339 2304
201201
/// file: src/routes/login/+page.server.js
202-
+import { invalid, redirect } from '@sveltejs/kit';
202+
+import { fail, redirect } from '@sveltejs/kit';
203203

204204
/** @type {import('./$types').Actions} */
205205
export const actions = {
@@ -210,11 +210,11 @@ export const actions = {
210210

211211
const user = await db.getUser(email);
212212
if (!user) {
213-
return invalid(400, { email, missing: true });
213+
return fail(400, { email, missing: true });
214214
}
215215

216216
if (user.password !== hash(password)) {
217-
return invalid(400, { email, incorrect: true });
217+
return fail(400, { email, incorrect: true });
218218
}
219219

220220
cookies.set('sessionid', await db.createSession(user));
@@ -377,7 +377,7 @@ If you provide your own callbacks, you may need to reproduce part of the default
377377

378378
The behaviour of `applyAction(result)` depends on `result.type`:
379379

380-
- `success`, `invalid` — sets `$page.status` to `result.status` and updates `form` and `$page.form` to `result.data` (regardless of where you are submitting from, in contrast to `update` from `enhance`)
380+
- `success`, `failure` — sets `$page.status` to `result.status` and updates `form` and `$page.form` to `result.data` (regardless of where you are submitting from, in contrast to `update` from `enhance`)
381381
- `redirect` — calls `goto(result.location)`
382382
- `error` — renders the nearest `+error` boundary with `result.error`
383383

packages/create-svelte/templates/default/src/routes/sverdle/+page.server.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { invalid } from '@sveltejs/kit';
1+
import { fail } from '@sveltejs/kit';
22
import { Game } from './game';
33
import type { PageServerLoad, Actions } from './$types';
44

@@ -59,7 +59,7 @@ export const actions = {
5959
const guess = /** @type {string[]} */ data.getAll('guess') /***/ as string[];
6060

6161
if (!game.enter(guess)) {
62-
return invalid(400, { badGuess: true });
62+
return fail(400, { badGuess: true });
6363
}
6464

6565
cookies.set('sverdle', game.toString());

packages/kit/src/exports/index.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { HttpError, Redirect, ValidationError } from '../runtime/control.js';
1+
import { HttpError, Redirect, ActionFailure } from '../runtime/control.js';
22

33
// For some reason we need to type the params as well here,
44
// JSdoc doesn't seem to like @type with function overloads
@@ -46,10 +46,15 @@ export function json(data, init) {
4646
}
4747

4848
/**
49-
* Generates a `ValidationError` object.
49+
* Generates an `ActionFailure` object.
5050
* @param {number} status
5151
* @param {Record<string, any> | undefined} [data]
5252
*/
53-
export function invalid(status, data) {
54-
return new ValidationError(status, data);
53+
export function fail(status, data) {
54+
return new ActionFailure(status, data);
55+
}
56+
57+
// TODO remove for 1.0
58+
export function invalid() {
59+
throw new Error('invalid(...) is now fail(...)');
5560
}

packages/kit/src/runtime/app/forms.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export function enhance(form, submit = () => {}) {
4747
await invalidateAll();
4848
}
4949

50-
// For success/invalid results, only apply action if it belongs to the
50+
// For success/failure results, only apply action if it belongs to the
5151
// current page, otherwise `form` will be updated erroneously
5252
if (
5353
location.origin + location.pathname === action.origin + action.pathname ||

packages/kit/src/runtime/control.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export class Redirect {
3333
/**
3434
* @template {Record<string, unknown> | undefined} [T=undefined]
3535
*/
36-
export class ValidationError {
36+
export class ActionFailure {
3737
/**
3838
* @param {number} status
3939
* @param {T} [data]

packages/kit/src/runtime/server/page/actions.js

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as devalue from 'devalue';
22
import { error, json } from '../../../exports/index.js';
33
import { normalize_error } from '../../../utils/error.js';
44
import { is_form_content_type, negotiate } from '../../../utils/http.js';
5-
import { HttpError, Redirect, ValidationError } from '../../control.js';
5+
import { HttpError, Redirect, ActionFailure } from '../../control.js';
66
import { handle_error_and_jsonify } from '../utils.js';
77

88
/** @param {import('types').RequestEvent} event */
@@ -50,9 +50,9 @@ export async function handle_action_json_request(event, options, server) {
5050
try {
5151
const data = await call_action(event, actions);
5252

53-
if (data instanceof ValidationError) {
53+
if (data instanceof ActionFailure) {
5454
return action_json({
55-
type: 'invalid',
55+
type: 'failure',
5656
status: data.status,
5757
// @ts-expect-error we assign a string to what is supposed to be an object. That's ok
5858
// because we don't use the object outside, and this way we have better code navigation
@@ -81,7 +81,7 @@ export async function handle_action_json_request(event, options, server) {
8181
return action_json(
8282
{
8383
type: 'error',
84-
error: await handle_error_and_jsonify(event, options, check_incorrect_invalid_use(error))
84+
error: await handle_error_and_jsonify(event, options, check_incorrect_fail_use(error))
8585
},
8686
{
8787
status: error instanceof HttpError ? error.status : 500
@@ -93,9 +93,9 @@ export async function handle_action_json_request(event, options, server) {
9393
/**
9494
* @param {HttpError | Error} error
9595
*/
96-
function check_incorrect_invalid_use(error) {
97-
return error instanceof ValidationError
98-
? new Error(`Cannot "throw invalid()". Use "return invalid()"`)
96+
function check_incorrect_fail_use(error) {
97+
return error instanceof ActionFailure
98+
? new Error(`Cannot "throw fail()". Use "return fail()"`)
9999
: error;
100100
}
101101

@@ -142,8 +142,8 @@ export async function handle_action_request(event, server) {
142142
try {
143143
const data = await call_action(event, actions);
144144

145-
if (data instanceof ValidationError) {
146-
return { type: 'invalid', status: data.status, data: data.data };
145+
if (data instanceof ActionFailure) {
146+
return { type: 'failure', status: data.status, data: data.data };
147147
} else {
148148
return {
149149
type: 'success',
@@ -164,7 +164,7 @@ export async function handle_action_request(event, server) {
164164

165165
return {
166166
type: 'error',
167-
error: check_incorrect_invalid_use(error)
167+
error: check_incorrect_fail_use(error)
168168
};
169169
}
170170
}
@@ -183,7 +183,7 @@ function check_named_default_separate(actions) {
183183
/**
184184
* @param {import('types').RequestEvent} event
185185
* @param {NonNullable<import('types').SSRNode['server']['actions']>} actions
186-
* @throws {Redirect | ValidationError | HttpError | Error}
186+
* @throws {Redirect | ActionFailure | HttpError | Error}
187187
*/
188188
export async function call_action(event, actions) {
189189
const url = new URL(event.request.url);

packages/kit/src/runtime/server/page/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export async function render_page(event, route, page, options, state, resolve_op
6868
const error = action_result.error;
6969
status = error instanceof HttpError ? error.status : 500;
7070
}
71-
if (action_result?.type === 'invalid') {
71+
if (action_result?.type === 'failure') {
7272
status = action_result.status;
7373
}
7474
}

packages/kit/src/runtime/server/page/render.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export async function render_response({
6767
let rendered;
6868

6969
const form_value =
70-
action_result?.type === 'success' || action_result?.type === 'invalid'
70+
action_result?.type === 'success' || action_result?.type === 'failure'
7171
? action_result.data ?? null
7272
: null;
7373

packages/kit/test/apps/basics/src/routes/actions/form-errors-persist-fields/+page.server.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { invalid } from '@sveltejs/kit';
1+
import { fail } from '@sveltejs/kit';
22

33
/**
44
* @type {import('./$types').Actions}
@@ -7,7 +7,7 @@ export const actions = {
77
default: async ({ request }) => {
88
const fields = await request.formData();
99
fields.delete('password');
10-
return invalid(400, {
10+
return fail(400, {
1111
values: Object.fromEntries(fields),
1212
errors: {
1313
message: 'invalid credentials'

0 commit comments

Comments
 (0)