Skip to main content

Fonctions distantes

Disponible depuis la version 2.27

Les fonctions distantes (remote functions) sont un outil pour communiquer de manière typée entre le client et le serveur. Elles peuvent être appelées depuis n’importe où dans votre application, mais sont toujours exécutées sur le serveur, ce qui signifie qu’elles peuvent accéder de manière sécurisée aux modules réservés au serveur contenant des choses comme des variables d’environnement ou des clients de base de données.

Combinées avec le support expérimental de Svelte pour await, elles vous permettent de charger et de manipuler les données directement au sein de vos composants.

Cette fonctionnalité est actuellement expérimentale, ce qui signifie qu’elle contient très certainement des bugs, et peut être modifiée à tout moment. Vous devez l’activer en ajoutant l’option kit.experimental.remoteFunctions dans votre fichier svelte.config.js, et de manière optionnelle en ajoutant l’option kit.experimental.remoteFunctions dans votre svelte.config.js :

svelte.config
/** @type {import('@sveltejs/kit').Config} */
const 
const config: {
    kit: {
        experimental: {
 remoteFunctions: boolean;
        };
    };
    compilerOptions: {
        experimental: {
 async: boolean;
        };
    };
}
@type{import('@sveltejs/kit').Config}
config
= {
kit: {
    experimental: {
        remoteFunctions: boolean;
    };
}
kit
: {
experimental: {
    remoteFunctions: boolean;
}
experimental
: {
remoteFunctions: booleanremoteFunctions: true } },
compilerOptions: {
    experimental: {
        async: boolean;
    };
}
compilerOptions
: {
experimental: {
    async: boolean;
}
experimental
: {
async: booleanasync: true } } }; export default
const config: {
    kit: {
        experimental: {
 remoteFunctions: boolean;
        };
    };
    compilerOptions: {
        experimental: {
 async: boolean;
        };
    };
}
@type{import('@sveltejs/kit').Config}
config
;

Aperçu

Les fonctions distantes (remote) sont exportées depuis un fichier .remote.js ou .remote.ts, et sont disponibles en quatre versions : query, form, command, et prerender. Sur le client, les fonctions exportées sont transformées en wrappers autour de fetch qui invoquent leur contrepartie sur le serveur en utilisant un endpoint HTTP généré. Les fichiers .remote. doivent être placés dans le dossier src.

query

La fonction query vous permet de lire des données dynamiques depuis le serveur (pour les données statiques, envisagez plutôt l’utilisation de prerender) :

src/routes/blog/data.remote
import { function query<Output>(fn: () => MaybePromise<Output>): RemoteQueryFunction<void, Output> (+2 overloads)

Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.

See Remote functions for full documentation.

@since2.27
query
} from '$app/server';
import * as module "$lib/server/database"db from '$lib/server/database'; export const const getPosts: RemoteQueryFunction<void, any[]>getPosts = query<any[]>(fn: () => MaybePromise<any[]>): RemoteQueryFunction<void, any[]> (+2 overloads)

Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.

See Remote functions for full documentation.

@since2.27
query
(async () => {
const const posts: any[]posts = await module "$lib/server/database"db.function sql(strings: TemplateStringsArray, ...values: any[]): Promise<any[]>sql` SELECT title, slug FROM post ORDER BY published_at DESC `; return const posts: any[]posts; });

Tout au long de cette page, vous verrez des imports depuis des modules fictifs comme $lib/server/database et $lib/server/auth. Ces imports n’existent que pour illustrer les propos — vous pouvez bien sûr utiliser n’importe quel client de base de données et n’importe quel système d’authentification.

La fonction db.sql ci-dessus est une fonction de gabarit étiquété qui échappe toute valeur interpolée.

La query renvoyée par getPosts fonctionne comme une Promise qui résout des posts :

src/routes/blog/+page
<script>
	import { getPosts } from './data.remote';
</script>

<h1>Articles récents</h1>

<ul>
	{#each await getPosts() as { title, slug }}
		<li><a href="/blog/{slug}">{title}</a></li>
	{/each}
</ul>
<script lang="ts">
	import { getPosts } from './data.remote';
</script>

<h1>Articles récents</h1>

<ul>
	{#each await getPosts() as { title, slug }}
		<li><a href="/blog/{slug}">{title}</a></li>
	{/each}
</ul>

Tant que la promesse n’est pas résolue — et si elle échoue — la <svelte:boundary> la plus proche sera invoquée.

Bien que l’utilisation de await soit recommandée, vous pouvez également utiliser en alternative les propriétés loading, error et current de la query :

src/routes/blog/+page
<script>
	import { getPosts } from './data.remote';

	const query = getPosts();
</script>

<h1>Articles récents</h1>

{#if query.error}
	<p>oups !</p>
{:else if query.loading}
	<p>chargement...</p>
{:else}
	<ul>
		{#each query.current as { title, slug }}
			<li><a href="/blog/{slug}">{title}</a></li>
		{/each}
	</ul>
{/if}
<script lang="ts">
	import { getPosts } from './data.remote';

	const query = getPosts();
</script>

<h1>Articles récents</h1>

{#if query.error}
	<p>oups !</p>
{:else if query.loading}
	<p>chargement...</p>
{:else}
	<ul>
		{#each query.current as { title, slug }}
			<li><a href="/blog/{slug}">{title}</a></li>
		{/each}
	</ul>
{/if}

Pour le reste de ce document, nous utiliserons la forme await.

Arguments de query

Les fonctions query peuvent accepter un argument, comme le slug d’un article individuel :

src/routes/blog/[slug]/+page
<script>
	import { getPost } from '../data.remote';

	let { params } = $props();

	const post = $derived(await getPost(params.slug));
</script>

<h1>{post.title}</h1>
<div>{@html post.content}</div>
<script lang="ts">
	import { getPost } from '../data.remote';

	let { params } = $props();

	const post = $derived(await getPost(params.slug));
</script>

<h1>{post.title}</h1>
<div>{@html post.content}</div>

Puisque getPost expose un endpoint HTTP, il est important de valider cet argument pour garantir qu’il est du type attendu. Pour cela, nous pouvons utiliser n’importe quelle librairie de validation de Standard Schema, comme Zod ou Valibot :

src/routes/blog/data.remote
import * as import vv from 'valibot';
import { function error(status: number, body: App.Error): never (+1 overload)

Throws an error with a HTTP status code and an optional message. When called during request handling, this will cause SvelteKit to return an error response without invoking handleError. Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it.

@paramstatus The HTTP status code. Must be in the range 400-599.
@parambody An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.
@throwsHttpError This error instructs SvelteKit to initiate HTTP error handling.
@throwsError If the provided status is invalid (not between 400 and 599).
error
} from '@sveltejs/kit';
import { function query<Output>(fn: () => MaybePromise<Output>): RemoteQueryFunction<void, Output> (+2 overloads)

Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.

See Remote functions for full documentation.

@since2.27
query
} from '$app/server';
import * as module "$lib/server/database"db from '$lib/server/database'; export const const getPosts: RemoteQueryFunction<void, void>getPosts = query<void>(fn: () => MaybePromise<void>): RemoteQueryFunction<void, void> (+2 overloads)

Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.

See Remote functions for full documentation.

@since2.27
query
(async () => { /* ... */ });
export const const getPost: RemoteQueryFunction<string, any>getPost = query<v.StringSchema<undefined>, any>(schema: v.StringSchema<undefined>, fn: (arg: string) => any): RemoteQueryFunction<string, any> (+2 overloads)

Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.

See Remote functions for full documentation.

@since2.27
query
(import vv.
function string(): v.StringSchema<undefined> (+1 overload)
export string

Creates a string schema.

@returnsA string schema.
string
(), async (slug: stringslug) => {
const [const post: anypost] = await module "$lib/server/database"db.function sql(strings: TemplateStringsArray, ...values: any[]): Promise<any[]>sql` SELECT * FROM post WHERE slug = ${slug: stringslug} `; if (!const post: anypost)
function error(status: number, body?: {
    message: string;
} extends App.Error ? App.Error | string | undefined : never): never (+1 overload)

Throws an error with a HTTP status code and an optional message. When called during request handling, this will cause SvelteKit to return an error response without invoking handleError. Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it.

@paramstatus The HTTP status code. Must be in the range 400-599.
@parambody An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.
@throwsHttpError This error instructs SvelteKit to initiate HTTP error handling.
@throwsError If the provided status is invalid (not between 400 and 599).
error
(404, 'Not found');
return const post: anypost; });

L’argument et la valeur de retour sont tous deux sérialisés avec devalue, qui gère des types comme Date et Map (et également des types personnalisés que vous pouvez définir dans votre transport hook) en plus du JSON.

Mettre les queries à jour

Toute query peut être rafraîchie via sa méthode refresh, qui récupère la valeur la plus récente depuis le serveur :

<button onclick={() => getPosts().refresh()}>
	Vérifier s'il y a des nouveaux articles
</button>

Les queries sont mises en cache tant qu’elles sont sur la page, ce qui veut dire que getPosts() === getPosts(). Cela signifie que vous n’avez pas besoin d’une référence comme const posts = getPosts() pour mettre à jour la query.

query.batch

query.batch fonctionne comme query à l’exception du fait qu’il regroupe les requêtes se produisant lors de la même micro-tâche. Ceci résout le bien nommé problème n+1 : plutôt que chaque requête résulte en un appel séparé à la base de données (par exemple), les requêtes simultanées sont regroupées.

Sur le serveur, le callback reçoit un tableau des arguments avec lesquels la fonction a été appelée. Il doit renvoyer une fonction de signature (input: Input, index: number) => Output. SvelteKit exécutera alors cette fonction avec chacun des arguments d’entrée pour résoudre les appels individuels et leurs résultats.

weather.remote
import * as import vv from 'valibot';
import { function query<Output>(fn: () => MaybePromise<Output>): RemoteQueryFunction<void, Output> (+2 overloads)

Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.

See Remote functions for full documentation.

@since2.27
query
} from '$app/server';
import * as module "$lib/server/database"db from '$lib/server/database'; export const const getWeather: RemoteQueryFunction<string, any>getWeather = function query<Output>(fn: () => MaybePromise<Output>): RemoteQueryFunction<void, Output> (+2 overloads)

Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.

See Remote functions for full documentation.

@since2.27
query
.function query.batch<v.StringSchema<undefined>, any>(schema: v.StringSchema<undefined>, fn: (args: string[]) => MaybePromise<(arg: string, idx: number) => any>): RemoteQueryFunction<string, any> (+1 overload)

Creates a batch query function that collects multiple calls and executes them in a single request

See Remote functions for full documentation.

@since2.35
batch
(import vv.
function string(): v.StringSchema<undefined> (+1 overload)
export string

Creates a string schema.

@returnsA string schema.
string
(), async (cities: string[]cities) => {
const const weather: any[]weather = await module "$lib/server/database"db.function sql(strings: TemplateStringsArray, ...values: any[]): Promise<any[]>sql` SELECT * FROM weather WHERE city = ANY(${cities: string[]cities}) `; const const lookup: Map<any, any>lookup = new
var Map: MapConstructor
new <any, any>(iterable?: Iterable<readonly [any, any]> | null | undefined) => Map<any, any> (+3 overloads)
Map
(const weather: any[]weather.Array<any>.map<[any, any]>(callbackfn: (value: any, index: number, array: any[]) => [any, any], thisArg?: any): [any, any][]

Calls a defined callback function on each element of an array, and returns an array that contains the results.

@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.
@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
(w: anyw => [w: anyw.city, w: anyw]));
return (city: stringcity) => const lookup: Map<any, any>lookup.Map<any, any>.get(key: any): any

Returns a specified element from the Map object. If the value that is associated to the provided key is an object, then you will get a reference to that object and any change made to that object will effectively modify it inside the Map.

@returnsReturns the element associated with the specified key. If no element is associated with the specified key, undefined is returned.
get
(city: stringcity);
});
Weather
<script>
	import CityWeather from './CityWeather.svelte';
	import { getWeather } from './weather.remote.js';

	let { cities } = $props();
	let limit = $state(5);
</script>

<h2>Weather</h2>

{#each cities.slice(0, limit) as city}
	<h3>{city.name}</h3>
	<CityWeather weather={await getWeather(city.id)} />
{/each}

{#if cities.length > limit}
	<button onclick={() => limit += 5}>
		Charger plus
	</button>
{/if}
<script lang="ts">
	import CityWeather from './CityWeather.svelte';
	import { getWeather } from './weather.remote.js';

	let { cities } = $props();
	let limit = $state(5);
</script>

<h2>Weather</h2>

{#each cities.slice(0, limit) as city}
	<h3>{city.name}</h3>
	<CityWeather weather={await getWeather(city.id)} />
{/each}

{#if cities.length > limit}
	<button onclick={() => limit += 5}>
		Charger plus
	</button>
{/if}

form

La fonction form facilite l’écriture de données sur le serveur. Elle prend un callback qui reçoit l’objet data construit à partir du FormData soumis...

src/routes/blog/data.remote
import * as import vv from 'valibot';
import { function error(status: number, body: App.Error): never (+1 overload)

Throws an error with a HTTP status code and an optional message. When called during request handling, this will cause SvelteKit to return an error response without invoking handleError. Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it.

@paramstatus The HTTP status code. Must be in the range 400-599.
@parambody An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.
@throwsHttpError This error instructs SvelteKit to initiate HTTP error handling.
@throwsError If the provided status is invalid (not between 400 and 599).
error
, function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): never

Redirect a request. When called during request handling, SvelteKit will return a redirect response. Make sure you’re not catching the thrown redirect, which would prevent SvelteKit from handling it.

Most common status codes:

  • 303 See Other: redirect as a GET request (often used after a form POST request)
  • 307 Temporary Redirect: redirect will keep the request method
  • 308 Permanent Redirect: redirect will keep the request method, SEO will be transferred to the new page

See all redirect status codes

@paramstatus The HTTP status code. Must be in the range 300-308.
@paramlocation The location to redirect to.
@throwsRedirect This error instructs SvelteKit to redirect to the specified location.
@throwsError If the provided status is invalid.
redirect
} from '@sveltejs/kit';
import { function query<Output>(fn: () => MaybePromise<Output>): RemoteQueryFunction<void, Output> (+2 overloads)

Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.

See Remote functions for full documentation.

@since2.27
query
, function form<Output>(fn: () => MaybePromise<Output>): RemoteForm<void, Output> (+2 overloads)

Creates a form object that can be spread onto a &#x3C;form> element.

See Remote functions for full documentation.

@since2.27
form
} from '$app/server';
import * as module "$lib/server/database"db from '$lib/server/database'; import * as module "$lib/server/auth"auth from '$lib/server/auth'; export const const getPosts: RemoteQueryFunction<void, void>getPosts = query<void>(fn: () => MaybePromise<void>): RemoteQueryFunction<void, void> (+2 overloads)

Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.

See Remote functions for full documentation.

@since2.27
query
(async () => { /* ... */ });
export const const getPost: RemoteQueryFunction<string, void>getPost = query<v.StringSchema<undefined>, void>(schema: v.StringSchema<undefined>, fn: (arg: string) => MaybePromise<void>): RemoteQueryFunction<string, void> (+2 overloads)

Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.

See Remote functions for full documentation.

@since2.27
query
(import vv.
function string(): v.StringSchema<undefined> (+1 overload)
export string

Creates a string schema.

@returnsA string schema.
string
(), async (slug: stringslug) => { /* ... */ });
export const
const createPost: RemoteForm<{
    title: string;
    content: string;
}, never>
createPost
=
form<v.ObjectSchema<{
    readonly title: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]>;
    readonly content: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]>;
}, undefined>, never>(validate: v.ObjectSchema<...>, fn: (data: {
    ...;
}) => Promise<...>): RemoteForm<...> (+2 overloads)

Creates a form object that can be spread onto a &#x3C;form> element.

See Remote functions for full documentation.

@since2.27
form
(
import vv.
object<{
    readonly title: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]>;
    readonly content: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]>;
}>(entries: {
    readonly title: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]>;
    readonly content: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]>;
}): v.ObjectSchema<...> (+1 overload)
export object

Creates an object schema.

Hint: This schema removes unknown entries. The output will only include the entries you specify. To include unknown entries, use looseObject. To return an issue for unknown entries, use strictObject. To include and validate unknown entries, use objectWithRest.

@paramentries The entries schema.
@returnsAn object schema.
object
({
title: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]>title: import vv.
pipe<v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>>(schema: v.StringSchema<undefined>, item1: v.NonEmptyAction<string, undefined> | v.PipeAction<string, string, v.NonEmptyIssue<...>>): v.SchemaWithPipe<...> (+20 overloads)
export pipe

Adds a pipeline to a schema, that can validate and transform its input.

@paramschema The root schema.
@paramitem1 The first pipe item.
@returnsA schema with a pipeline.
pipe
(import vv.
function string(): v.StringSchema<undefined> (+1 overload)
export string

Creates a string schema.

@returnsA string schema.
string
(), import vv.
nonEmpty<string>(): v.NonEmptyAction<string, undefined> (+1 overload)
export nonEmpty

Creates a non-empty validation action.

@returnsA non-empty action.
nonEmpty
()),
content: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]>content:import vv.
pipe<v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>>(schema: v.StringSchema<undefined>, item1: v.NonEmptyAction<string, undefined> | v.PipeAction<string, string, v.NonEmptyIssue<...>>): v.SchemaWithPipe<...> (+20 overloads)
export pipe

Adds a pipeline to a schema, that can validate and transform its input.

@paramschema The root schema.
@paramitem1 The first pipe item.
@returnsA schema with a pipeline.
pipe
(import vv.
function string(): v.StringSchema<undefined> (+1 overload)
export string

Creates a string schema.

@returnsA string schema.
string
(), import vv.
nonEmpty<string>(): v.NonEmptyAction<string, undefined> (+1 overload)
export nonEmpty

Creates a non-empty validation action.

@returnsA non-empty action.
nonEmpty
())
}), async ({ title: stringtitle, content: stringcontent }) => { // Vérifie si l'utilisateur est loggué const const user: auth.User | nulluser = await module "$lib/server/auth"auth.function getUser(): Promise<auth.User | null>

Récupère les informations de l’utilisateur à partir des cookies, en utilisant getRequestEvent

getUser
();
if (!const user: auth.User | nulluser)
function error(status: number, body?: {
    message: string;
} extends App.Error ? App.Error | string | undefined : never): never (+1 overload)

Throws an error with a HTTP status code and an optional message. When called during request handling, this will cause SvelteKit to return an error response without invoking handleError. Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it.

@paramstatus The HTTP status code. Must be in the range 400-599.
@parambody An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.
@throwsHttpError This error instructs SvelteKit to initiate HTTP error handling.
@throwsError If the provided status is invalid (not between 400 and 599).
error
(401, 'Unauthorized');
const const slug: stringslug = title: stringtitle.String.toLowerCase(): string

Converts all the alphabetic characters in a string to lowercase.

toLowerCase
().
String.replace(searchValue: {
    [Symbol.replace](string: string, replaceValue: string): string;
}, replaceValue: string): string (+3 overloads)

Passes a string and {@linkcode replaceValue } to the [Symbol.replace] method on {@linkcode searchValue } . This method is expected to implement its own replacement algorithm.

@paramsearchValue An object that supports searching for and replacing matches within a string.
@paramreplaceValue The replacement text.
replace
(/ /g, '-');
// Insère dans la base de données await module "$lib/server/database"db.function sql(strings: TemplateStringsArray, ...values: any[]): Promise<any[]>sql` INSERT INTO post (slug, title, content) VALUES (${const slug: stringslug}, ${title: stringtitle}, ${content: stringcontent}) `; // Redirige vers la page nouvellement créée function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): never

Redirect a request. When called during request handling, SvelteKit will return a redirect response. Make sure you’re not catching the thrown redirect, which would prevent SvelteKit from handling it.

Most common status codes:

  • 303 See Other: redirect as a GET request (often used after a form POST request)
  • 307 Temporary Redirect: redirect will keep the request method
  • 308 Permanent Redirect: redirect will keep the request method, SEO will be transferred to the new page

See all redirect status codes

@paramstatus The HTTP status code. Must be in the range 300-308.
@paramlocation The location to redirect to.
@throwsRedirect This error instructs SvelteKit to redirect to the specified location.
@throwsError If the provided status is invalid.
redirect
(303, `/blog/${const slug: stringslug}`);
} )

... et renvoie un objet qui peut être distribué sur un élément <form>. Le callback est appelée à chaque fois que le formulaire est soumis.

src/routes/blog/new/+page
<script>
	import { createPost } from '../data.remote';
</script>

<h1>Créer un nouvel article</h1>

<form {...createPost}>
	<!-- le contenu du formulaire est défini ici -->

	<button>Publier !</button>
</form>
<script lang="ts">
	import { createPost } from '../data.remote';
</script>

<h1>Créer un nouvel article</h1>

<form {...createPost}>
	<!-- le contenu du formulaire est défini ici -->

	<button>Publier !</button>
</form>

L’objet de formulaire contient les propriétés method et action qui lui permettent de fonctionner sans JavaScriptt (c-à-d il soumet les données et recharge la page). Il possède également un attachement qui améliore progressivement le formulaire lorsque JavaScript est disponible, lui permettant de soumettre les données sans recharger entièrement la page.

Comme avec query, si le callback utilise les data soumises, celles-ci doivent être validées en passant un Standard Schema en tant que premier argument au form.

Champs

Un formulaire est composé d’un ensemble de champs, qui sont définis par le schéma. Dans le cas d’un createPost, nous avons deux champs, title et content, qui sont tous deux des chaînes de caractères. Pour récupérer les attributs d’un champ, exécutez sa méthode as(...), en précisant quel type d’input utiliser :

<form {...createPost}>
	<label>
		<h2>Titre</h2>
		<input {...createPost.fields.title.as('text')} />
	</label>

	<label>
		<h2>Écrivez votre article</h2>
		<textarea {...createPost.fields.content.as('text')}></textarea>
	</label>

	<button>Publier !</button>
</form>

Ces attributs permettent à SvelteKit de définit le type correct d’input, de définir un name utilisé pour construire les data passées au gestionnaire, de remplir la value du formulaire (par exemple à la suite de l’échec d’une soumission, permettant de sauvegarder l’utilisateur ou l’utilisatrice sans avoir besoin de tout ré-écrire), et de définir l’état aria-invalid

Les champs peuvent être imbriqués dans des objets et des tableaux, et leurs valeurs peuvent être des chaînes de caractères, des nombres, des booléens ou des objets File. Par exemple, si votre schéma ressemble à ceci...

data.remote
const 
const datingProfile: v.ObjectSchema<{
    readonly name: v.StringSchema<undefined>;
    readonly photo: v.FileSchema<undefined>;
    readonly info: v.ObjectSchema<{
        readonly height: v.NumberSchema<undefined>;
        readonly likesDogs: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
    }, undefined>;
    readonly attributes: v.ArraySchema<...>;
}, undefined>
datingProfile
= import vv.
object<{
    readonly name: v.StringSchema<undefined>;
    readonly photo: v.FileSchema<undefined>;
    readonly info: v.ObjectSchema<{
        readonly height: v.NumberSchema<undefined>;
        readonly likesDogs: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
    }, undefined>;
    readonly attributes: v.ArraySchema<...>;
}>(entries: {
    readonly name: v.StringSchema<undefined>;
    readonly photo: v.FileSchema<undefined>;
    readonly info: v.ObjectSchema<{
        readonly height: v.NumberSchema<undefined>;
        readonly likesDogs: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
    }, undefined>;
    readonly attributes: v.ArraySchema<...>;
}): v.ObjectSchema<...> (+1 overload)
export object

Creates an object schema.

Hint: This schema removes unknown entries. The output will only include the entries you specify. To include unknown entries, use looseObject. To return an issue for unknown entries, use strictObject. To include and validate unknown entries, use objectWithRest.

@paramentries The entries schema.
@returnsAn object schema.
object
({
name: v.StringSchema<undefined>name: import vv.
function string(): v.StringSchema<undefined> (+1 overload)
export string

Creates a string schema.

@returnsA string schema.
string
(),
photo: v.FileSchema<undefined>photo: import vv.
function file(): v.FileSchema<undefined> (+1 overload)
export file

Creates a file schema.

@returnsA file schema.
file
(),
info: v.ObjectSchema<{
    readonly height: v.NumberSchema<undefined>;
    readonly likesDogs: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
}, undefined>
info
: import vv.
object<{
    readonly height: v.NumberSchema<undefined>;
    readonly likesDogs: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
}>(entries: {
    readonly height: v.NumberSchema<undefined>;
    readonly likesDogs: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
}): v.ObjectSchema<...> (+1 overload)
export object

Creates an object schema.

Hint: This schema removes unknown entries. The output will only include the entries you specify. To include unknown entries, use looseObject. To return an issue for unknown entries, use strictObject. To include and validate unknown entries, use objectWithRest.

@paramentries The entries schema.
@returnsAn object schema.
object
({
height: v.NumberSchema<undefined>height: import vv.
function number(): v.NumberSchema<undefined> (+1 overload)
export number

Creates a number schema.

@returnsA number schema.
number
(),
likesDogs: v.OptionalSchema<v.BooleanSchema<undefined>, false>likesDogs: import vv.
optional<v.BooleanSchema<undefined>, false>(wrapped: v.BooleanSchema<undefined>, default_: false): v.OptionalSchema<v.BooleanSchema<undefined>, false> (+1 overload)
export optional

Creates an optional schema.

@paramwrapped The wrapped schema.
@paramdefault_ The default value.
@returnsAn optional schema.
optional
(import vv.
function boolean(): v.BooleanSchema<undefined> (+1 overload)
export boolean

Creates a boolean schema.

@returnsA boolean schema.
boolean
(), false)
}), attributes: v.ArraySchema<v.StringSchema<undefined>, undefined>attributes: import vv.
array<v.StringSchema<undefined>>(item: v.StringSchema<undefined>): v.ArraySchema<v.StringSchema<undefined>, undefined> (+1 overload)
export array

Creates an array schema.

@paramitem The item schema.
@returnsAn array schema.
array
(import vv.
function string(): v.StringSchema<undefined> (+1 overload)
export string

Creates a string schema.

@returnsA string schema.
string
())
}); export const
const createProfile: RemoteForm<{
    name: string;
    photo: File;
    info: {
        height: number;
        likesDogs?: boolean | undefined;
    };
    attributes: string[];
}, void>
createProfile
=
form<v.ObjectSchema<{
    readonly name: v.StringSchema<undefined>;
    readonly photo: v.FileSchema<undefined>;
    readonly info: v.ObjectSchema<{
        readonly height: v.NumberSchema<undefined>;
        readonly likesDogs: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
    }, undefined>;
    readonly attributes: v.ArraySchema<...>;
}, undefined>, void>(validate: v.ObjectSchema<...>, fn: (data: {
    ...;
}) => MaybePromise<...>): RemoteForm<...> (+2 overloads)

Creates a form object that can be spread onto a &#x3C;form> element.

See Remote functions for full documentation.

@since2.27
form
(
const datingProfile: v.ObjectSchema<{
    readonly name: v.StringSchema<undefined>;
    readonly photo: v.FileSchema<undefined>;
    readonly info: v.ObjectSchema<{
        readonly height: v.NumberSchema<undefined>;
        readonly likesDogs: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
    }, undefined>;
    readonly attributes: v.ArraySchema<...>;
}, undefined>
datingProfile
, (
data: {
    name: string;
    photo: File;
    info: {
        height: number;
        likesDogs: boolean;
    };
    attributes: string[];
}
data
) => { /* ... */ });

... votre formulaire pourrait avoir cette forme là :

<script>
	import { createProfile } from './data.remote';

	const { name, photo, info, attributes } = createProfile.fields;
</script>

<form {...createProfile} enctype="multipart/form-data">
	<label>
		<input {...name.as('text')} /> Nom
	</label>

	<label>
		<input {...photo.as('file')} /> Photo
	</label>

	<label>
		<input {...info.height.as('number')} /> Hauteur (cm)
	</label>

	<label>
		<input {...info.likesDogs.as('checkbox')} /> J'aime les chiens
	</label>

	<h2>Mes meilleures compétences</h2>
	<input {...attributes[0].as('text')} />
	<input {...attributes[1].as('text')} />
	<input {...attributes[2].as('text')} />

	<button>envoyer</button>
</form>

Puisque notre formulaire contient un input file, nous avons ajouté un attribut enctype="multipart/form-data". Les valeurs de info.height et info.likesDogs sont transformées en nombre et booléen respectivement.

Si un input checkbox est non coché, sa valeur n’est pas incluses dans l’objet FormData à partir duquelSvelteKit construit les données. Ainsi, nous devons rendre la valeur optionnelle dans votre schéma. Avec Valibot cela signifie l’utilisation de v.optional(v.boolean(), false) plutôt que juste v.boolean(), tandis qu’avec Zod, cela signifie l’utilisation de z.coerce.boolean<boolean>().

Dans le cas d’inputs radio et checkbox qui appartiennent tous au même champ, la value doit être précisée en tant que second argument de .as(...) :

data.remote
export const 
const survey: RemoteForm<{
    operatingSystem: "windows" | "mac" | "linux";
    languages?: ("html" | "css" | "js")[] | undefined;
}, void>
survey
=
form<v.ObjectSchema<{
    readonly operatingSystem: v.PicklistSchema<["windows", "mac", "linux"], undefined>;
    readonly languages: v.OptionalSchema<v.ArraySchema<v.PicklistSchema<["html", "css", "js"], undefined>, undefined>, readonly []>;
}, undefined>, void>(validate: v.ObjectSchema<...>, fn: (data: {
    ...;
}) => MaybePromise<...>): RemoteForm<...> (+2 overloads)

Creates a form object that can be spread onto a &#x3C;form> element.

See Remote functions for full documentation.

@since2.27
form
(
import vv.
object<{
    readonly operatingSystem: v.PicklistSchema<["windows", "mac", "linux"], undefined>;
    readonly languages: v.OptionalSchema<v.ArraySchema<v.PicklistSchema<["html", "css", "js"], undefined>, undefined>, readonly []>;
}>(entries: {
    readonly operatingSystem: v.PicklistSchema<["windows", "mac", "linux"], undefined>;
    readonly languages: v.OptionalSchema<v.ArraySchema<v.PicklistSchema<["html", "css", "js"], undefined>, undefined>, readonly []>;
}): v.ObjectSchema<...> (+1 overload)
export object

Creates an object schema.

Hint: This schema removes unknown entries. The output will only include the entries you specify. To include unknown entries, use looseObject. To return an issue for unknown entries, use strictObject. To include and validate unknown entries, use objectWithRest.

@paramentries The entries schema.
@returnsAn object schema.
object
({
operatingSystem: v.PicklistSchema<["windows", "mac", "linux"], undefined>operatingSystem: import vv.
picklist<["windows", "mac", "linux"]>(options: ["windows", "mac", "linux"]): v.PicklistSchema<["windows", "mac", "linux"], undefined> (+1 overload)
export picklist

Creates a picklist schema.

@paramoptions The picklist options.
@returnsA picklist schema.
picklist
(['windows', 'mac', 'linux']),
languages: v.OptionalSchema<v.ArraySchema<v.PicklistSchema<["html", "css", "js"], undefined>, undefined>, readonly []>languages: import vv.
optional<v.ArraySchema<v.PicklistSchema<["html", "css", "js"], undefined>, undefined>, readonly []>(wrapped: v.ArraySchema<v.PicklistSchema<["html", "css", "js"], undefined>, undefined>, default_: readonly []): v.OptionalSchema<...> (+1 overload)
export optional

Creates an optional schema.

@paramwrapped The wrapped schema.
@paramdefault_ The default value.
@returnsAn optional schema.
optional
(import vv.
array<v.PicklistSchema<["html", "css", "js"], undefined>>(item: v.PicklistSchema<["html", "css", "js"], undefined>): v.ArraySchema<v.PicklistSchema<["html", "css", "js"], undefined>, undefined> (+1 overload)
export array

Creates an array schema.

@paramitem The item schema.
@returnsAn array schema.
array
(import vv.
picklist<["html", "css", "js"]>(options: ["html", "css", "js"]): v.PicklistSchema<["html", "css", "js"], undefined> (+1 overload)
export picklist

Creates a picklist schema.

@paramoptions The picklist options.
@returnsA picklist schema.
picklist
(['html', 'css', 'js'])), [])
}), (
data: {
    operatingSystem: "windows" | "mac" | "linux";
    languages: ("html" | "css" | "js")[];
}
data
) => { /* ... */ }
);
<form {...survey}>
	<h2>Quel système d'exploitation utilisez-vous ?</h2>

	{#each ['windows', 'mac', 'linux'] as os}
		<label>
			<input {...survey.fields.operatingSystem.as('radio', os)}>
			{os}
		</label>
	{/each}

	<h2>Dans quels langages écrivez-vous du code ?</h2>

	{#each ['html', 'css', 'js'] as language}
		<label>
			<input {...survey.fields.languages.as('checkbox', language)}>
			{language}
		</label>
	{/each}

	<button>envoyer</button>
</form>

De manière alternative, vous pouvez également utiliser select et select multiple :

<form {...survey}>
	<h2>Quel système d'exploitation utilisez-vous ?</h2>

	<select {...survey.fields.operatingSystem.as('select')}>
		<option>windows</option>
		<option>mac</option>
		<option>linux</option>
	</select>

	<h2>Dans quels langages écrivez-vous du code ?</h2>

	<select {...survey.fields.languages.as('select multiple')}>
		<option>html</option>
		<option>css</option>
		<option>js</option>
	</select>

	<button>envoyer</button>
</form>

Comme pour les inputs checkbox non cochés, si aucune sélection n’est faite, alors les données seront undefined. Pour cette raison, le champ languages utilise v.optional(v.array(...), []), plutôt que simplement v.array(...).

Validation programmatique

En plus de la validation de schéma déclarative, vous pouvez programmatiquement marquer des champs comme invalides au sein du gestionnaire de formulaire en utilisant la fonction invalid. Cela sert dans les cas où vous ne pouvez savoir si quelque chose est valide avant d’avoir effectué certaines actions :

src/routes/shop/data.remote
import * as import vv from 'valibot';
import { function form<Output>(fn: () => MaybePromise<Output>): RemoteForm<void, Output> (+2 overloads)

Creates a form object that can be spread onto a &#x3C;form> element.

See Remote functions for full documentation.

@since2.27
form
} from '$app/server';
import * as import dbdb from '$lib/server/database'; export const const buyHotcakes: RemoteForm<RemoteFormInput, unknown>buyHotcakes = form<RemoteFormInput, unknown>(validate: "unchecked", fn: (data: RemoteFormInput) => unknown): RemoteForm<RemoteFormInput, unknown> (+2 overloads)

Creates a form object that can be spread onto a &#x3C;form> element.

See Remote functions for full documentation.

@since2.27
form
(
import vv.
object<{
    readonly qty: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.MinValueAction<number, 1, "vous devez acheter au moins un gâteau">]>;
}>(entries: {
    readonly qty: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.MinValueAction<number, 1, "vous devez acheter au moins un gâteau">]>;
}): v.ObjectSchema<...> (+1 overload)
export object

Creates an object schema.

Hint: This schema removes unknown entries. The output will only include the entries you specify. To include unknown entries, use looseObject. To return an issue for unknown entries, use strictObject. To include and validate unknown entries, use objectWithRest.

@paramentries The entries schema.
@returnsAn object schema.
object
({
qty: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.MinValueAction<number, 1, "vous devez acheter au moins un gâteau">]>qty: import vv.
pipe<v.NumberSchema<undefined>, v.MinValueAction<number, 1, "vous devez acheter au moins un gâteau">>(schema: v.NumberSchema<undefined>, item1: v.MinValueAction<number, 1, "vous devez acheter au moins un gâteau"> | v.PipeAction<...>): v.SchemaWithPipe<...> (+20 overloads)
export pipe

Adds a pipeline to a schema, that can validate and transform its input.

@paramschema The root schema.
@paramitem1 The first pipe item.
@returnsA schema with a pipeline.
pipe
(
import vv.
function number(): v.NumberSchema<undefined> (+1 overload)
export number

Creates a number schema.

@returnsA number schema.
number
(),
import vv.
minValue<number, 1, "vous devez acheter au moins un gâteau">(requirement: 1, message: "vous devez acheter au moins un gâteau"): v.MinValueAction<number, 1, "vous devez acheter au moins un gâteau"> (+1 overload)
export minValue

Creates a min value validation action.

@paramrequirement The minimum value.
@parammessage The error message.
@returnsA min value action.
minValue
(1, 'vous devez acheter au moins un gâteau')
) }), async (data: anydata, invalid: anyinvalid) => { try { await import dbdb.buy(data: anydata.qty); } catch (function (local var) e: unknowne) { if (function (local var) e: unknowne.code === 'OUT_OF_STOCK') { invalid: anyinvalid( invalid: anyinvalid.qty(`nous n'avons pas assez de gâteaux`) ); } } } );

La fonction invalid fonctionne à la fois comme une fonction et comme un proxy :

  • Appelez invalid(issue1, issue2, ...issueN) pour jeter une erreur de validation
  • Si une erreur est une string, elle s’applique au formulaire en tant que tel (et sera affichée dans fields.allIssues())
  • Utilisez invalid.fieldName(message) pour créer une erreur pour un champ particulier. Comme fields, ceci est typé et vous pouvez utiliser la syntaxe classique d’accès aux propriétés pour créer des erreurs concernant des objets imbriqués (par ex. invalid.profile.email('L\'e-mail existe déjà'') ou invalid.items[0].qty('Stock insuffisant')))

Validation

Si les données soumises ne correspondent pas au schéma, le callback ne sera pas exécuté. À la place, chaque méthode issues() d’un champ invalide renverra un tableau d’objets { message: string }, et l’attribut aria-invalid (renvoyé depuis as(...)) sera défini comme true :

<form {...createPost}>
	<label>
		<h2>Title</h2>

		{#each createPost.fields.title.issues() as issue}
			<p class="issue">{issue.message}</p>
		{/each}

		<input {...createPost.fields.title.as('text')} />
	</label>

	<label>
		<h2>Écrivez votre article</h2>

		{#each createPost.fields.content.issues() as issue}
			<p class="issue">{issue.message}</p>
		{/each}

		<textarea {...createPost.fields.content.as('text')}></textarea>
	</label>

	<button>Publier !</button>
</form>

Vous n’avez pas besoin d’attendre la fin de la soumission du formulaire pour valider les données — vous pouvez appeler validate() programmatiquement, par exemple dans un callback oninput (qui va valider les données à chaque touche du clavier) ou dans un callback onchange :

<form {...createPost} oninput={() => createPost.validate()}>
	<!-- -->
</form>

Par défaut, les problèmes sont ignorés s’ils concernent des contrôles de formulaires avec lesquels il n’y a pas encore eu d’interaction. Pour valider tous les inputs, appelez validate({ includeUntouched: true }).

Pour les validations côté client, vous pouvez préciser un schéma preflight qui va remplir les issues() et empêcher que les données soient envoyées au serveur si celles-ci ne sont pas validées :

<script>
	import * as v from 'valibot';
	import { createPost } from '../data.remote';

	const schema = v.object({
		title: v.pipe(v.string(), v.nonEmpty()),
		content: v.pipe(v.string(), v.nonEmpty())
	});
</script>

<h1>Créer un nouvel article</h1>

<form {...createPost.preflight(schema)}>
	<!-- -->
</form>

Le schéma preflight peut être le même objet que votre schéma utilisé sur le serveur, si cela est pertinent, même s’il ne sera pas capable de faire des validations devant être faites côté serveur comme “cette valeur existe déjà dans la base de données” par exemple. Notez que vous ne pouvez pas exporter un schéma depuis un fichier .remote.ts ou .remote.js, le schéma doit alors être exporté depuis un module partagé, ou depuis le block <script module> du composant contenant le <form>.

Pour obtenir une liste de tous les problèmes, plutôt qu’uniquement ceux appartenant à un champ particulier, vous pouvez utiliser la méthode fields.allIssues() :

{#each createPost.fields.allIssues() as issue}
	<p>{issue.message}</p>
{/each}

Récupérer/définir des inputs

Chaque champ a une méthode value() qui reflète sa valeur actuelle. Lorsque quelqu’un interagit avec le formulaire, la valeur est automatiquement mise à jour :

<form {...createPost}>
	<!-- -->
</form>

<div class="preview">
	<h2>{createPost.fields.title.value()}</h2>
	<div>{@html render(createPost.fields.content.value())}</div>
</div>

De plus, createPost.fields renvoie un objet { title, content }.

Vous pouvez mettre à jour un champ (ou une collection de champs) via la méthode set(...) :

<script>
	import { createPost } from '../data.remote';

	// ceci...
	createPost.fields.set({
		title: 'Mon nouvel article de blog',
		content: 'Lorem ipsum dolor sit amet...'
	});

	// ...est équivalent à ceci :
	createPost.fields.title.set('Mon nouvel article de blog');
	createPost.fields.content.set('Lorem ipsum dolor sit amet');
</script>

Gérer les données sensibles

Dans le cas d’une soumission de formulaire non-améliorée-progressivement (c-à-d lorsque JavaScript n’est pas disponible, quelqu’en soit la raison), value() est également rempli si les données soumises sont invalides, afin que l’utilisateur ou l’utilisatrice n’ait pas besoin de re-remplir entièrement le formulaire.

Vous pouvez empêcher que des données sensibles (comme des mots de passe ou des numéros de carte bancaire) soient renvoyés au client en utilisant un nom commençant par un tiret-bas :

<form {...register}>
	<label>
		Nom
		<input {...register.fields.username.as('text')} />
	</label>

	<label>
		Mot de passe
		<input {...register.fields._password.as('password')} />
	</label>

	<button>S'inscrire !</button>
</form>

Dans cet exemple, si les données ne sont pas validées, seul le premier <input> sera rempli lorsque la page sera rechargée.

Mutations single-flight

Par défaut, toutes les queries utilisées sur la page (en plus de toutes fonction load) sont automatiquement mises à jour à la suite d’une soumission de formulaire. Ceci assure que tout soit à jour, mais est également inefficace : beaucoup de queries seront inchangées, et cela requiert un deuxième aller-retour vers le serveur pour obtenir les données à jour.

À la place, nous pouvons préciser quelles queries devraient être mises à jour en réponse à une soumission particulière de formulaire. On appelle cela une mutation single-flight (mutation sur un seul aller-retour), et il y a deux manières de faire. La première est de rafraîchir la query sur le serveur, dans le gestionnaire de formulaire :

export const const getPosts: RemoteQueryFunction<void, void>getPosts = query<void>(fn: () => MaybePromise<void>): RemoteQueryFunction<void, void> (+2 overloads)

Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.

See Remote functions for full documentation.

@since2.27
query
(async () => { /* ... */ });
export const const getPost: RemoteQueryFunction<string, void>getPost = query<v.StringSchema<undefined>, void>(schema: v.StringSchema<undefined>, fn: (arg: string) => MaybePromise<void>): RemoteQueryFunction<string, void> (+2 overloads)

Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.

See Remote functions for full documentation.

@since2.27
query
(import vv.
function string(): v.StringSchema<undefined> (+1 overload)
export string

Creates a string schema.

@returnsA string schema.
string
(), async (slug: stringslug) => { /* ... */ });
export const const createPost: RemoteForm<{}, never>createPost = form<v.ObjectSchema<{}, undefined>, never>(validate: v.ObjectSchema<{}, undefined>, fn: (data: {}) => Promise<never>): RemoteForm<{}, never> (+2 overloads)

Creates a form object that can be spread onto a &#x3C;form> element.

See Remote functions for full documentation.

@since2.27
form
(
import vv.
object<{}>(entries: {}): v.ObjectSchema<{}, undefined> (+1 overload)
export object

Creates an object schema.

Hint: This schema removes unknown entries. The output will only include the entries you specify. To include unknown entries, use looseObject. To return an issue for unknown entries, use strictObject. To include and validate unknown entries, use objectWithRest.

@paramentries The entries schema.
@returnsAn object schema.
object
({/* ... */}),
async (data: {}data) => { // la logique du formulaire se place ici... // Met à jour `getPosts()` sur le serveur, et // renvoie les données au client avec le résultat // de `createPost` await const getPosts: (arg: void) => RemoteQuery<void>getPosts().function refresh(): Promise<void>

On the client, this function will re-fetch the query from the server.

On the server, this can be called in the context of a command or form and the refreshed data will accompany the action response back to the client. This prevents SvelteKit needing to refresh all queries on the page in a second server round-trip.

refresh
();
// Redirige vers la page nouvellement créée function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): never

Redirect a request. When called during request handling, SvelteKit will return a redirect response. Make sure you’re not catching the thrown redirect, which would prevent SvelteKit from handling it.

Most common status codes:

  • 303 See Other: redirect as a GET request (often used after a form POST request)
  • 307 Temporary Redirect: redirect will keep the request method
  • 308 Permanent Redirect: redirect will keep the request method, SEO will be transferred to the new page

See all redirect status codes

@paramstatus The HTTP status code. Must be in the range 300-308.
@paramlocation The location to redirect to.
@throwsRedirect This error instructs SvelteKit to redirect to the specified location.
@throwsError If the provided status is invalid.
redirect
(303, `/blog/${const slug: ""slug}`);
} ); export const const updatePost: RemoteForm<{}, void>updatePost = form<v.ObjectSchema<{}, undefined>, void>(validate: v.ObjectSchema<{}, undefined>, fn: (data: {}) => MaybePromise<void>): RemoteForm<{}, void> (+2 overloads)

Creates a form object that can be spread onto a &#x3C;form> element.

See Remote functions for full documentation.

@since2.27
form
(
import vv.
object<{}>(entries: {}): v.ObjectSchema<{}, undefined> (+1 overload)
export object

Creates an object schema.

Hint: This schema removes unknown entries. The output will only include the entries you specify. To include unknown entries, use looseObject. To return an issue for unknown entries, use strictObject. To include and validate unknown entries, use objectWithRest.

@paramentries The entries schema.
@returnsAn object schema.
object
({/* ... */}),
async (data: {}data) => { // la logique de formulaire s'écrit ici... const const result: anyresult = const externalApi: any
@type{any}
externalApi
.update(
const post: {
    id: string;
}
post
);
// L'API nous donne déjà l'article mis à jour, // il n'y donc pas besoin de le rafraîchir, nous pouvons le définir directement await const getPost: (arg: string) => RemoteQuery<void>getPost(
const post: {
    id: string;
}
post
.id: stringid).function set(value: void): void

On the client, this function will update the value of the query without re-fetching it.

On the server, this can be called in the context of a command or form and the specified data will accompany the action response back to the client. This prevents SvelteKit needing to refresh all queries on the page in a second server round-trip.

set
(const result: anyresult);
} );

La seconde est de conduire la mutation single-flight depuis le client, ce que nous verrons dans la section sur enhance.

Renvois et redirections

L’exemple ci-dessus utilise redirect(...), qui redirige l’utilisateur ou l’utilisatrice vers la page nouvellement créée. De manière alternative, le callback pourrait également renvoyer les données, auquel cas elles seraient disponibles en tant que createPost.result :

src/routes/blog/data.remote
export const 
const createPost: RemoteForm<{}, {
    success: boolean;
}>
createPost
=
form<v.ObjectSchema<{}, undefined>, {
    success: boolean;
}>(validate: v.ObjectSchema<{}, undefined>, fn: (data: {}) => MaybePromise<{
    success: boolean;
}>): RemoteForm<{}, {
    success: boolean;
}> (+2 overloads)

Creates a form object that can be spread onto a &#x3C;form> element.

See Remote functions for full documentation.

@since2.27
form
(
import vv.
object<{}>(entries: {}): v.ObjectSchema<{}, undefined> (+1 overload)
export object

Creates an object schema.

Hint: This schema removes unknown entries. The output will only include the entries you specify. To include unknown entries, use looseObject. To return an issue for unknown entries, use strictObject. To include and validate unknown entries, use objectWithRest.

@paramentries The entries schema.
@returnsAn object schema.
object
({/* ... */}),
async (data: {}data) => { // ... return { success: booleansuccess: true }; } );
src/routes/blog/new/+page
<script>
	import { createPost } from '../data.remote';
</script>

<h1>Créer un nouvel article</h1>

<form {...createPost}>
	<!-- -->
</form>

{#if createPost.result?.success}
	<p>Publié avec succès !</p>
{/if}
<script lang="ts">
	import { createPost } from '../data.remote';
</script>

<h1>Créer un nouvel article</h1>

<form {...createPost}>
	<!-- -->
</form>

{#if createPost.result?.success}
	<p>Publié avec succès !</p>
{/if}

Cette valeur est éphémère — elle disparaîtra si vous re-soumettez le formulaire, si vous naviguez sur une autre page, ou si vous rechargez la page.

La valeur de result n’indique pas nécessairement un succès — elle peut également contenir des erreurs de validation, ainsi que des données permettant de re-remplir le formulaire en cas de rechargement de la page.

Si une erreur se produit lors de la soumission, la page +error.svelte la plus proche sera affichée.

enhance

Nous pouvons personnaliser ce qui se produit lorsque le formulaire est soumis grâce à la méthode enhance :

src/routes/blog/new/+page
<script>
	import { createPost } from '../data.remote';
	import { showToast } from '$lib/toast';
</script>

<h1>Créer un nouvel article</h1>

<form {...createPost.enhance(async ({ form, data, submit }) => {
	try {
		await submit();
		form.reset();

		showToast('Publié avec succès !');
	} catch (error) {
		showToast('Oh non ! Quelque chose s\'est mal passé !');
	}
})}>
	<!-- -->
</form>
<script lang="ts">
	import { createPost } from '../data.remote';
	import { showToast } from '$lib/toast';
</script>

<h1>Créer un nouvel article</h1>

<form {...createPost.enhance(async ({ form, data, submit }) => {
	try {
		await submit();
		form.reset();

		showToast('Publié avec succès !');
	} catch (error) {
		showToast('Oh non ! Quelque chose s\'est mal passé !');
	}
})}>
	<!-- -->
</form>

Lorsque vous utilisez enhance, le <form> n’est pas automatiquement réinitialisé — vous devez appeler form.reset() si vous souhaitez nettoyer les inputs.

Le callback reçoit l’élément form, la data qu’il contient, et une fonction submit.

Pour activer les mutations single-flight depuis le client, utilisez submit().updates(...}). Par exemple, si la query getPosts() était utilisée sur cette page, nous pourrions la mettre à jour de cette manière :

await 
function submit(): Promise<any> & {
    updates(...queries: Array<RemoteQuery<any> | RemoteQueryOverride>): Promise<any>;
}
submit
().function updates(...queries: Array<RemoteQuery<any> | RemoteQueryOverride>): Promise<any>updates(function getPosts(): RemoteQuery<Post[]>getPosts());

Nous pouvons aussi surcharger les données courantes pendant que la soumission est en cours de traitement :

await 
function submit(): Promise<any> & {
    updates(...queries: Array<RemoteQuery<any> | RemoteQueryOverride>): Promise<any>;
}
submit
().function updates(...queries: Array<RemoteQuery<any> | RemoteQueryOverride>): Promise<any>updates(
function getPosts(): RemoteQuery<Post[]>getPosts().function withOverride(update: (current: Post[]) => Post[]): RemoteQueryOverride

Temporarily override the value of a query. This is used with the updates method of a command or enhanced form submission to provide optimistic updates.

&#x3C;script>
  import { getTodos, addTodo } from './todos.remote.js';
  const todos = getTodos();
&#x3C;/script>

&#x3C;form {...addTodo.enhance(async ({ data, submit }) => {
  await submit().updates(
	todos.withOverride((todos) => [...todos, { text: data.get('text') }])
  );
})}>
  &#x3C;input type="text" name="text" />
  &#x3C;button type="submit">Add Todo&#x3C;/button>
&#x3C;/form>
withOverride
((posts: Post[]posts) => [const newPost: PostnewPost, ...posts: Post[]posts])
);

La surcharge sera appliquée immédiatement, et annulée lorsque la soumission se termine (ou échoue).

Instances multiples de formulaire

Certains formulaires peuvent être répétés au sein d’une liste. Dans ce cas, vous pouvez créer des instances séparées d’une fonction de formulaire via for(id) pour les garder en isolation.

src/routes/todos/+page
<script>
	import { getTodos, modifyTodo } from '../data.remote';
</script>

<h1>À faire</h1>

{#each await getTodos() as todo}
	{@const modify = modifyTodo.for(todo.id)}
	<form {...modify}>
		<!-- -->
		<button disabled={!!modify.pending}>enregistrer les changements</button>
	</form>
{/each}
<script lang="ts">
	import { getTodos, modifyTodo } from '../data.remote';
</script>

<h1>À faire</h1>

{#each await getTodos() as todo}
	{@const modify = modifyTodo.for(todo.id)}
	<form {...modify}>
		<!-- -->
		<button disabled={!!modify.pending}>enregistrer les changements</button>
	</form>
{/each}

buttonProps

Par défaut, soumettre un formulaire va envoyer une requête à l’URL indiquée par l’attribut action de l’élément <form>, ce qui dans le cas d’une fonction distante est une propriété sur l’objet de formulaire généré par SvelteKit.

Il est possible pour un <button> au sein d’un <form> d’envoyer la requête à une URL différente, en utilisant l’attribut formaction. Par exemple, vous pourriez avoir un seul formulaire vous permettant de vous connecter ou de vous inscrire, selon le bouton sur lequel vous cliquez.

Cet attribut existe dans la propriété buttonProps d’un objet de formulaire :

src/routes/login/+page
<script>
	import { login, register } from '$lib/auth';
</script>

<form {...login}>
	<label>
		Votre nom d'utilisateur
		<input {...login.fields.username.as('text')} />
	</label>

	<label>
		Votre mot de passe
		<input {...login.fields._password.as('password')} />
	</label>

	<button>se connecter</button>
	<button {...register.buttonProps}>s'inscrire</button>
</form>
<script lang="ts">
	import { login, register } from '$lib/auth';
</script>

<form {...login}>
	<label>
		Votre nom d'utilisateur
		<input {...login.fields.username.as('text')} />
	</label>

	<label>
		Votre mot de passe
		<input {...login.fields._password.as('password')} />
	</label>

	<button>se connecter</button>
	<button {...register.buttonProps}>s'inscrire</button>
</form>

Comme l’objet de formulaire lui-même, buttonProps possède une méthode enhance permettant de personnaliser la soumission du formulaire.

command

La fonction command, comme form, vous permet d’écrire des données sur le serveur. À la différence de form, elle n’est pas spécifique à un élément et peut être appelée depuis n’importe où.

Privilégiez l’usage de form lorsque c’est possible, puisqu’elle continue de fonctionner lorsque JavaScript est désactivé ou a échoué à se charger.

Comme avec query et form, si la fonction accepte un argument, celui-ci devrait être validé en fournissant un Standard Schema en tant que premier argument à command.

likes.remote
import * as import vv from 'valibot';
import { function query<Output>(fn: () => MaybePromise<Output>): RemoteQueryFunction<void, Output> (+2 overloads)

Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.

See Remote functions for full documentation.

@since2.27
query
, function command<Output>(fn: () => Output): RemoteCommand<void, Output> (+2 overloads)

Creates a remote command. When called from the browser, the function will be invoked on the server via a fetch call.

See Remote functions for full documentation.

@since2.27
command
} from '$app/server';
import * as module "$lib/server/database"db from '$lib/server/database'; export const const getLikes: RemoteQueryFunction<string, any>getLikes = query<v.StringSchema<undefined>, any>(schema: v.StringSchema<undefined>, fn: (arg: string) => any): RemoteQueryFunction<string, any> (+2 overloads)

Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.

See Remote functions for full documentation.

@since2.27
query
(import vv.
function string(): v.StringSchema<undefined> (+1 overload)
export string

Creates a string schema.

@returnsA string schema.
string
(), async (id: stringid) => {
const [const row: anyrow] = await module "$lib/server/database"db.function sql(strings: TemplateStringsArray, ...values: any[]): Promise<any[]>sql` SELECT likes FROM item WHERE id = ${id: stringid} `; return const row: anyrow.likes; }); export const const addLike: RemoteCommand<string, Promise<void>>addLike = command<v.StringSchema<undefined>, Promise<void>>(validate: v.StringSchema<undefined>, fn: (arg: string) => Promise<void>): RemoteCommand<string, Promise<void>> (+2 overloads)

Creates a remote command. When called from the browser, the function will be invoked on the server via a fetch call.

See Remote functions for full documentation.

@since2.27
command
(import vv.
function string(): v.StringSchema<undefined> (+1 overload)
export string

Creates a string schema.

@returnsA string schema.
string
(), async (id: stringid) => {
await module "$lib/server/database"db.function sql(strings: TemplateStringsArray, ...values: any[]): Promise<any[]>sql` UPDATE item SET likes = likes + 1 WHERE id = ${id: stringid} `; });

Vous pouvez maintenant simplement appeler addLike, depuis (par exemple) un gestionnaire d’évènement :

+page
<script>
	import { getLikes, addLike } from './likes.remote';
	import { showToast } from '$lib/toast';

	let { item } = $props();
</script>

<button
	onclick={async () => {
		try {
			await addLike(item.id);
		} catch (error) {
			showToast('Quelque chose s\'est mal passé !');
		}
	}}
>
	ajouter un like
</button>

<p>likes : {await getLikes(item.id)}</p>
<script lang="ts">
	import { getLikes, addLike } from './likes.remote';
	import { showToast } from '$lib/toast';

	let { item } = $props();
</script>

<button
	onclick={async () => {
		try {
			await addLike(item.id);
		} catch (error) {
			showToast('Quelque chose s\'est mal passé !');
		}
	}}
>
	ajouter un like
</button>

<p>likes : {await getLikes(item.id)}</p>

Les commandes ne peuvent pas être appelées lors du rendu.

Mettre à jour les queries

Pour mettre à jour getLikes(item.id), ou toute autre query, nous avons besoin de préciser à SvelteKit quelles queries nécessitent d’être rafraîchies (au contraire de form, qui invalide tout par défaut, pour se rapprocher du comportement natif d’une soumission de formulaire).

Nous faisons cela soit au sein de la commande elle-même...

likes.remote
export const const getLikes: RemoteQueryFunction<string, void>getLikes = query<v.StringSchema<undefined>, void>(schema: v.StringSchema<undefined>, fn: (arg: string) => MaybePromise<void>): RemoteQueryFunction<string, void> (+2 overloads)

Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.

See Remote functions for full documentation.

@since2.27
query
(import vv.
function string(): v.StringSchema<undefined> (+1 overload)
export string

Creates a string schema.

@returnsA string schema.
string
(), async (id: stringid) => { /* ... */ });
export const const addLike: RemoteCommand<string, Promise<void>>addLike = command<v.StringSchema<undefined>, Promise<void>>(validate: v.StringSchema<undefined>, fn: (arg: string) => Promise<void>): RemoteCommand<string, Promise<void>> (+2 overloads)

Creates a remote command. When called from the browser, the function will be invoked on the server via a fetch call.

See Remote functions for full documentation.

@since2.27
command
(import vv.
function string(): v.StringSchema<undefined> (+1 overload)
export string

Creates a string schema.

@returnsA string schema.
string
(), async (id: stringid) => {
await module "$lib/server/database"db.function sql(strings: TemplateStringsArray, ...values: any[]): Promise<any[]>sql` UPDATE item SET likes = likes + 1 WHERE id = ${id: stringid} `; const getLikes: (arg: string) => RemoteQuery<void>getLikes(id: stringid).function refresh(): Promise<void>

On the client, this function will re-fetch the query from the server.

On the server, this can be called in the context of a command or form and the refreshed data will accompany the action response back to the client. This prevents SvelteKit needing to refresh all queries on the page in a second server round-trip.

refresh
();
// Comme au sein des fonctions de formulaire, nous pouvons aussi faire // getLikes(id).set(...) // dans le cas où vous avez déjà le résultat });

... soit lorsque nous l’exécutons :

try {
	await 
const addLike: (arg: string) => Promise<void> & {
    updates(...queries: Array<RemoteQuery<any> | RemoteQueryOverride>): Promise<...>;
}
addLike
(const item: Itemitem.Item.id: stringid).function updates(...queries: Array<RemoteQuery<any> | RemoteQueryOverride>): Promise<void>updates(const getLikes: (arg: string) => RemoteQuery<number>getLikes(const item: Itemitem.Item.id: stringid));
} catch (var error: unknownerror) { function showToast(message: string): voidshowToast('Quelque chose s\'est mal passé !'); }

Comme précédemment, nous pouvons utiliser withOverride pour faire des mises à jour optimistes :

try {
	await 
const addLike: (arg: string) => Promise<void> & {
    updates(...queries: Array<RemoteQuery<any> | RemoteQueryOverride>): Promise<...>;
}
addLike
(const item: Itemitem.Item.id: stringid).function updates(...queries: Array<RemoteQuery<any> | RemoteQueryOverride>): Promise<void>updates(
const getLikes: (arg: string) => RemoteQuery<number>getLikes(const item: Itemitem.Item.id: stringid).function withOverride(update: (current: number) => number): RemoteQueryOverride

Temporarily override the value of a query. This is used with the updates method of a command or enhanced form submission to provide optimistic updates.

&#x3C;script>
  import { getTodos, addTodo } from './todos.remote.js';
  const todos = getTodos();
&#x3C;/script>

&#x3C;form {...addTodo.enhance(async ({ data, submit }) => {
  await submit().updates(
	todos.withOverride((todos) => [...todos, { text: data.get('text') }])
  );
})}>
  &#x3C;input type="text" name="text" />
  &#x3C;button type="submit">Add Todo&#x3C;/button>
&#x3C;/form>
withOverride
((n: numbern) => n: numbern + 1)
); } catch (var error: unknownerror) { function showToast(message: string): voidshowToast('Quelque chose s\'est mal passé !'); }

prerender

La fonction prerender est similaire à query, sauf qu’elle sera exécutée lors de la compilation pour pré-rendre le résultat. Utilisez cette fonction pour des données qui changent au plus une fois par déploiement.

src/routes/blog/data.remote
import { 
function prerender<Output>(fn: () => MaybePromise<Output>, options?: {
    inputs?: RemotePrerenderInputsGenerator<void>;
    dynamic?: boolean;
} | undefined): RemotePrerenderFunction<void, Output> (+2 overloads)

Creates a remote prerender function. When called from the browser, the function will be invoked on the server via a fetch call.

See Remote functions for full documentation.

@since2.27
prerender
} from '$app/server';
import * as module "$lib/server/database"db from '$lib/server/database'; export const const getPosts: RemotePrerenderFunction<void, any[]>getPosts =
prerender<any[]>(fn: () => MaybePromise<any[]>, options?: {
    inputs?: RemotePrerenderInputsGenerator<void>;
    dynamic?: boolean;
} | undefined): RemotePrerenderFunction<...> (+2 overloads)

Creates a remote prerender function. When called from the browser, the function will be invoked on the server via a fetch call.

See Remote functions for full documentation.

@since2.27
prerender
(async () => {
const const posts: any[]posts = await module "$lib/server/database"db.function sql(strings: TemplateStringsArray, ...values: any[]): Promise<any[]>sql` SELECT title, slug FROM post ORDER BY published_at DESC `; return const posts: any[]posts; });

Vous pouvez utiliser des fonctions prerender sur des pages par ailleurs dynamiques, permettant le pré-rendu partiel de vos données. Ceci permet une navigation très rapide, puisque les données prérendues peuvent être stockées sur un CDN à côté de vos autres assets statiques.

Dans le navigateur, les données pré-rendues sont sauvegardées en utilisant l’API Cache. Ce cache survit aux rechargements de page, et sera nettoyé lorsque l’utilisateur ou l’utilisatrice visitera pour la première fois une nouveau déploiement de votre application.

Lorsque la page entière a export const prerender = true, vous ne pouvez pas utiliser de queries, puisqu’elles sont dynamiques.

Arguments de prerender

Comme avec les queries, les fonctions prerender peuvent accepter un argument, qui devrait être validé avec un Standard Schema :

src/routes/blog/data.remote
import * as import vv from 'valibot';
import { function error(status: number, body: App.Error): never (+1 overload)

Throws an error with a HTTP status code and an optional message. When called during request handling, this will cause SvelteKit to return an error response without invoking handleError. Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it.

@paramstatus The HTTP status code. Must be in the range 400-599.
@parambody An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.
@throwsHttpError This error instructs SvelteKit to initiate HTTP error handling.
@throwsError If the provided status is invalid (not between 400 and 599).
error
} from '@sveltejs/kit';
import {
function prerender<Output>(fn: () => MaybePromise<Output>, options?: {
    inputs?: RemotePrerenderInputsGenerator<void>;
    dynamic?: boolean;
} | undefined): RemotePrerenderFunction<void, Output> (+2 overloads)

Creates a remote prerender function. When called from the browser, the function will be invoked on the server via a fetch call.

See Remote functions for full documentation.

@since2.27
prerender
} from '$app/server';
import * as module "$lib/server/database"db from '$lib/server/database'; export const const getPosts: RemotePrerenderFunction<void, void>getPosts =
prerender<void>(fn: () => MaybePromise<void>, options?: {
    inputs?: RemotePrerenderInputsGenerator<void>;
    dynamic?: boolean;
} | undefined): RemotePrerenderFunction<...> (+2 overloads)

Creates a remote prerender function. When called from the browser, the function will be invoked on the server via a fetch call.

See Remote functions for full documentation.

@since2.27
prerender
(async () => { /* ... */ });
export const const getPost: RemotePrerenderFunction<string, any>getPost =
prerender<v.StringSchema<undefined>, any>(schema: v.StringSchema<undefined>, fn: (arg: string) => any, options?: {
    inputs?: RemotePrerenderInputsGenerator<string> | undefined;
    dynamic?: boolean;
} | undefined): RemotePrerenderFunction<...> (+2 overloads)

Creates a remote prerender function. When called from the browser, the function will be invoked on the server via a fetch call.

See Remote functions for full documentation.

@since2.27
prerender
(import vv.
function string(): v.StringSchema<undefined> (+1 overload)
export string

Creates a string schema.

@returnsA string schema.
string
(), async (slug: stringslug) => {
const [const post: anypost] = await module "$lib/server/database"db.function sql(strings: TemplateStringsArray, ...values: any[]): Promise<any[]>sql` SELECT * FROM post WHERE slug = ${slug: stringslug} `; if (!const post: anypost)
function error(status: number, body?: {
    message: string;
} extends App.Error ? App.Error | string | undefined : never): never (+1 overload)

Throws an error with a HTTP status code and an optional message. When called during request handling, this will cause SvelteKit to return an error response without invoking handleError. Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it.

@paramstatus The HTTP status code. Must be in the range 400-599.
@parambody An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.
@throwsHttpError This error instructs SvelteKit to initiate HTTP error handling.
@throwsError If the provided status is invalid (not between 400 and 599).
error
(404, 'Not found');
return const post: anypost; });

Tout appel à getPost(...) identifié par le crawler de SvelteKit lors du pré-rendu des pages sera automatiquement enregistré, mais vous pouvez également préciser avec quelles valeurs chaque appel devrait être fait en utilisant l’option inputs :

src/routes/blog/data.remote

export const const getPost: RemotePrerenderFunction<string, void>getPost = 
prerender<v.StringSchema<undefined>, void>(schema: v.StringSchema<undefined>, fn: (arg: string) => MaybePromise<void>, options?: {
    inputs?: RemotePrerenderInputsGenerator<string> | undefined;
    dynamic?: boolean;
} | undefined): RemotePrerenderFunction<...> (+2 overloads)

Creates a remote prerender function. When called from the browser, the function will be invoked on the server via a fetch call.

See Remote functions for full documentation.

@since2.27
prerender
(
import vv.
function string(): v.StringSchema<undefined> (+1 overload)
export string

Creates a string schema.

@returnsA string schema.
string
(),
async (slug: stringslug) => { /* ... */ }, { inputs?: RemotePrerenderInputsGenerator<string> | undefinedinputs: () => [ 'premier-article', 'deuxième-article', 'troisième-article' ] } );
export const const getPost: RemotePrerenderFunction<string, void>getPost = 
prerender<v.StringSchema<undefined>, void>(schema: v.StringSchema<undefined>, fn: (arg: string) => MaybePromise<void>, options?: {
    inputs?: RemotePrerenderInputsGenerator<string> | undefined;
    dynamic?: boolean;
} | undefined): RemotePrerenderFunction<...> (+2 overloads)

Creates a remote prerender function. When called from the browser, the function will be invoked on the server via a fetch call.

See Remote functions for full documentation.

@since2.27
prerender
(
import vv.
function string(): v.StringSchema<undefined> (+1 overload)
export string

Creates a string schema.

@returnsA string schema.
string
(),
async (slug: stringslug) => { /* ... */ }, { inputs?: RemotePrerenderInputsGenerator<string> | undefinedinputs: () => [ 'premier-article', 'deuxième-article', 'troisième-article' ] } );

Svelte ne supporte pas encore le rendu asynchrone côté serveur, et il est donc probable que vous n’appeliez les fonctions distantes que depuis le serveur, plutôt que lors du pré-rendu. À cause de cela, vous aurez besoin d’utiliser inputs, pour le moment. Nous travaillons activement sur point bloquant.

Par défaut, les fonctions de pré-rendu sont exclues de votre bundle de compilation, ce qui signifie que vous ne pouvez pas les exécuter avec des arguments qui n’ont pas été pré-rendus. Vous pouvez définir dynamic: true pour changer ce comportement :

src/routes/blog/data.remote

export const const getPost: RemotePrerenderFunction<string, void>getPost = 
prerender<v.StringSchema<undefined>, void>(schema: v.StringSchema<undefined>, fn: (arg: string) => MaybePromise<void>, options?: {
    inputs?: RemotePrerenderInputsGenerator<string> | undefined;
    dynamic?: boolean;
} | undefined): RemotePrerenderFunction<...> (+2 overloads)

Creates a remote prerender function. When called from the browser, the function will be invoked on the server via a fetch call.

See Remote functions for full documentation.

@since2.27
prerender
(
import vv.
function string(): v.StringSchema<undefined> (+1 overload)
export string

Creates a string schema.

@returnsA string schema.
string
(),
async (slug: stringslug) => { /* ... */ }, { dynamic?: boolean | undefineddynamic: true, inputs?: RemotePrerenderInputsGenerator<string> | undefinedinputs: () => [ 'premier-article', 'deuxième-article', 'troisième-article' ] } );
export const const getPost: RemotePrerenderFunction<string, void>getPost = 
prerender<v.StringSchema<undefined>, void>(schema: v.StringSchema<undefined>, fn: (arg: string) => MaybePromise<void>, options?: {
    inputs?: RemotePrerenderInputsGenerator<string> | undefined;
    dynamic?: boolean;
} | undefined): RemotePrerenderFunction<...> (+2 overloads)

Creates a remote prerender function. When called from the browser, the function will be invoked on the server via a fetch call.

See Remote functions for full documentation.

@since2.27
prerender
(
import vv.
function string(): v.StringSchema<undefined> (+1 overload)
export string

Creates a string schema.

@returnsA string schema.
string
(),
async (slug: stringslug) => { /* ... */ }, { dynamic?: boolean | undefineddynamic: true, inputs?: RemotePrerenderInputsGenerator<string> | undefinedinputs: () => [ 'premier-article', 'deuxième-article', 'troisième-article' ] } );

Gestion des erreurs de validation

Tant que vous ne passez pas de données invalides à vos fonctions distantes, il n’y a que deux raisons pour lesquelles l’argument passé à une command, une query ou une prerender échouerait à la validation :

  • la signature de la fonction a changé entre deux déploiements, et certains utilisateurs ou utilisatrices sont actuellement sur une version ancienne de votre application
  • quelqu’un est en train d’essayer d’attaquer votre site en testant les endpoints que vous exposez avec des données malformées

Dans le second cas, nous ne voulons pas donner à l’attaquant d’indices, c’est pourquoi SvelteKit va générer une réponse générique 400 Bad Request. Vous pouvez contrôler le message en implémentant le hook serveur handleValidationError, qui, comme handleError, doit renvoyer un objet App.Error (qui est défini par défaut à { message: string }) :

src/hooks.server
/** @type {import('@sveltejs/kit').HandleValidationError} */
export function 
function handleValidationError({ event, issues }: {
    event: any;
    issues: any;
}): {
    message: string;
}
@type{import('@sveltejs/kit').HandleValidationError}
handleValidationError
({ event: anyevent, issues: anyissues }) {
return { message: stringmessage: 'Bien tenté, hacker !' }; }
import type { 
type HandleValidationError<Issue extends StandardSchemaV1.Issue = StandardSchemaV1.Issue> = (input: {
    issues: Issue[];
    event: RequestEvent;
}) => MaybePromise<App.Error>

The handleValidationError hook runs when the argument to a remote function fails validation.

It will be called with the validation issues and the event, and must return an object shape that matches App.Error.

HandleValidationError
} from '@sveltejs/kit';
export const const handleValidationError: HandleValidationErrorhandleValidationError:
type HandleValidationError<Issue extends StandardSchemaV1.Issue = StandardSchemaV1.Issue> = (input: {
    issues: Issue[];
    event: RequestEvent;
}) => MaybePromise<App.Error>

The handleValidationError hook runs when the argument to a remote function fails validation.

It will be called with the validation issues and the event, and must return an object shape that matches App.Error.

HandleValidationError
= ({ event: RequestEvent<Record<string, string>, string | null>event, issues: StandardSchemaV1.Issue[]issues }) => {
return { App.Error.message: stringmessage: 'Bien tenté, hacker !' }; };

Si vous savez ce que vous faites et souhaitez vous passer de validation, vous pouvez passer la chaîne de caractères 'unchecked' à la place du schéma :

data.remote
import { function query<Output>(fn: () => MaybePromise<Output>): RemoteQueryFunction<void, Output> (+2 overloads)

Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.

See Remote functions for full documentation.

@since2.27
query
} from '$app/server';
export const
const getStuff: RemoteQueryFunction<{
    id: string;
}, void>
getStuff
=
query<{
    id: string;
}, void>(validate: "unchecked", fn: (arg: {
    id: string;
}) => MaybePromise<void>): RemoteQueryFunction<{
    id: string;
}, void> (+2 overloads)

Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.

See Remote functions for full documentation.

@since2.27
query
('unchecked', async ({ id: stringid }: { id: stringid: string }) => {
// la forme peut ne pas être ce que pense TypeScript // puisque des personnes mal intentionnées pourraient // appeler cette fonction avec d'autres arguments });

Utiliser getRequestEvent

Dans une fonction query, form ou command, vous pouvez utiliser getRequestEvent pour obtenir l’objet RequestEvent courant. Ceci permet de construire simplement des abstractions pour interagir avec des cookies, par exemple :

user.remote
import { function getRequestEvent(): RequestEvent

Returns the current RequestEvent. Can be used inside server hooks, server load functions, actions, and endpoints (and functions called by them).

In environments without AsyncLocalStorage, this must be called synchronously (i.e. not after an await).

@since2.20.0
getRequestEvent
, function query<Output>(fn: () => MaybePromise<Output>): RemoteQueryFunction<void, Output> (+2 overloads)

Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.

See Remote functions for full documentation.

@since2.27
query
} from '$app/server';
import { import findUserfindUser } from '$lib/server/database'; export const
const getProfile: RemoteQueryFunction<void, {
    name: any;
    avatar: any;
}>
getProfile
=
query<{
    name: any;
    avatar: any;
}>(fn: () => MaybePromise<{
    name: any;
    avatar: any;
}>): RemoteQueryFunction<void, {
    name: any;
    avatar: any;
}> (+2 overloads)

Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.

See Remote functions for full documentation.

@since2.27
query
(async () => {
const const user: anyuser = await const getUser: (arg: void) => RemoteQuery<any>getUser(); return { name: anyname: const user: anyuser.name, avatar: anyavatar: const user: anyuser.avatar }; }); // cette query pourrait être appelée depuis plusieurs endroits, // mais cette fonction ne sera exécutée qu'une fois par requête const const getUser: RemoteQueryFunction<void, any>getUser = query<any>(fn: () => any): RemoteQueryFunction<void, any> (+2 overloads)

Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.

See Remote functions for full documentation.

@since2.27
query
(() => {
const { const cookies: Cookies

Get or set cookies related to the current request

cookies
} = function getRequestEvent(): RequestEvent

Returns the current RequestEvent. Can be used inside server hooks, server load functions, actions, and endpoints (and functions called by them).

In environments without AsyncLocalStorage, this must be called synchronously (i.e. not after an await).

@since2.20.0
getRequestEvent
();
return await import findUserfindUser(const cookies: Cookies

Get or set cookies related to the current request

cookies
.Cookies.get: (name: string, opts?: CookieParseOptions) => string | undefined

Gets a cookie that was previously set with cookies.set, or from the request headers.

@paramname the name of the cookie
@paramopts the options, passed directly to cookie.parse. See documentation here
get
('session_id'));
});

Notez que certaines propriétés de RequestEvent sont différentes au sein des fonctions distantes :

  • vous ne pouvez pas définir d’en-têtes (si ce n’est écrire dans des cookies, et uniquement dans des fonctions form et command)
  • route, params et url sont relatives à la page depuis laquelle la fonction distante a été appelée, et non l’URL du endpoint que SvelteKit crée pour la fonction distante. Les queries ne sont pas ré-exécutées lorsque l’utilisateur ou l’utilisatrice navigue (à moins que l’argument de la query ait changé suite à une navigation), vous devriez donc être conscient•e de la façon dont vous utilisez ces valeurs. En particulier, ne les utilisez jamais pour déterminer si oui ou non une personne est autorisée à accéder à certaines données.

Redirections

Au sein d’une fonction query, form ou prerender, il est possible d’utiliser la fonction redirect(...). Ce n’est pas possible au sein d’une fonction command, car vous devriez éviter de rediriger à cet endroit. (Si vous avez absolument besoin de le faire, vous pouvez toujours renvoyer un objet { redirect: location } et gérer la redirection côté client.)

Modifier cette page sur Github llms.txt