Guides
Validation
La validation est attachée au spec, pas à l’UI. C’est cette seule décision qui permet au navigateur et à votre backend d’aboutir au même verdict à partir du même fichier — aucun schéma à synchroniser à la main, aucune règle qui n’existe que côté client.
Validateurs déclaratifs
Section intitulée « Validateurs déclaratifs »Chaque brick porte un tableau validations. Ils sont compilés en JSON Schema
(Ajv + ajv-errors + ajv-formats) au moment du rendu :
| Validateur | S’applique à | value |
|---|---|---|
required |
tout | — |
minLength / maxLength |
chaîne | nombre |
pattern |
chaîne | source de regex |
email / url |
chaîne | — |
min / max |
nombre | nombre |
minItems / maxItems |
tableau | nombre |
custom |
tout | — (utilise customValidator) |
{ "validations": [ { "validator": "required" }, { "validator": "email", "message": "Saisissez une adresse valide" } ]}message est optionnel et peut être localisé — voir
messages et locales plus bas.
Validateurs personnalisés
Section intitulée « Validateurs personnalisés »Quand les onze validateurs intégrés ne suffisent pas, custom exécute un
extrait de code dans le bac à sable des règles :
// `value` est la valeur de ce champ, `dataMap` est tout le formulairereturn value !== dataMap.oldEmail || "Doit différer de l'adresse actuelle"La valeur retournée décide du résultat :
| Retour | Résultat |
|---|---|
true, undefined, null |
passe |
| une chaîne | échoue, et la chaîne devient le message |
une Error |
échoue avec error.message |
| tout le reste | échoue avec le message configuré, ou le message par défaut intégré |
Messages et locales
Section intitulée « Messages et locales »Les messages se résolvent en cascade : d’abord le message de l’auteur, puis
les messages par défaut de FormKrafter pour la locale active. L’anglais et le
français sont fournis d’office.
{ "validator": "required", "message": { "en": "Required", "fr": "Obligatoire" } }Enregistrez d’autres langues au démarrage :
import { registerValidationMessages } from '@streamline-pulse/formkrafter-core'
registerValidationMessages('de', { required: 'Pflichtfeld', minLength: 'Mindestens {value} Zeichen',})Le placeholder {value} est interpolé avec le paramètre du validateur.
Le même verdict côté serveur
Section intitulée « Le même verdict côté serveur »validateFormData est le point d’entrée backend. Il prend le même spec, le
payload soumis et une locale optionnelle :
import { validateFormData } from '@streamline-pulse/formkrafter-core'import type { BrickSpec } from '@streamline-pulse/formkrafter-core'
export function checkSubmission(spec: BrickSpec, payload: unknown) { const { valid, errors } = validateFormData(spec, payload, 'fr') if (!valid) throw new Error(JSON.stringify(errors)) return payload}// Le renderer expose la même passe sous forme de méthodeconst { valid, errors } = await formEl.validate()Il reproduit trois comportements du frontend qu’un contrôle backend écrit à la main rate facilement :
- Les lignes de collection sont validées individuellement, et remontent sous
la forme
contacts[0].email. - Les chaînes vides comptent comme absentes, si bien que
requiredse comporte comme ce que l’utilisateur a vu. - Les champs cachés par une règle sont exclus. Un champ obligatoire à l’étape 3 qu’une règle masque ne peut jamais bloquer une soumission dont il ne fait pas partie.
Quand une règle n’est pas appliquée
Section intitulée « Quand une règle n’est pas appliquée »Un spec peut porter des validations qui ne s’exécutent jamais. valid: true
signifie alors rien n’a objecté, et non les règles sont passées — une nuance
qui reste invisible jusqu’à ce que de mauvaises données soient déjà stockées.
validateFormData la remonte via warnings :
const { valid, errors, warnings } = validateFormData(spec, payload)
if (warnings) { console.warn(`${formId} accepte des soumissions sans certaines de ses règles :`) for (const warning of warnings) console.warn(` • ${warning}`)}warnings est absent sur un spec sain : sa seule présence est le signal. Il ne
change jamais valid — le verdict tient, il est simplement plus faible qu’il
n’en a l’air. Deux causes le produisent : un champ portant des validations
mais pas de dataType, ce qui ne laisse rien pour construire un schéma, et un
schéma dont la compilation a échoué, par exemple un pattern à la regex
invalide.
Linter les specs avant leur mise en service
Section intitulée « Linter les specs avant leur mise en service »warnings attrape le problème au moment de la soumission. lintSpec l’attrape
avant même que le spec ne soit stocké — il parcourt un spec et renvoie tout ce
qui y est structurellement faux, sans aucune donnée :
import { lintSpec } from '@streamline-pulse/formkrafter-core'
for (const issue of lintSpec(spec)) { console.error(`[${issue.code}] ${issue.path} — ${issue.message}`)}issue.code |
Signification |
|---|---|
validations-without-data-type |
La brick a des règles mais pas de dataType : aucune n’est appliquée |
input-without-key |
La valeur n’a nulle part où aller dans les données du formulaire |
duplicate-key |
Deux bricks écrivent sur la même clé ; une valeur écrase l’autre |
collection-without-children |
Une collection sans brick à répéter |
Chaque problème porte code, path, key et un message lisible. Un tableau
vide signifie que le spec est sain. C’est assez peu coûteux pour tourner en CI
sur chaque spec que vous semez ou générez, et sortir en erreur sur un résultat
non vide transforme toute une classe de bugs de données silencieux en build
rouge.
Étapes suivantes
Section intitulée « Étapes suivantes »Un projet de Streamline Pulse