Skip to content

Server Integration & Persistence

Server-side validation errors

Map a backend's validation error response onto form.errors — no hand-rolled unwrapping in every project.

ts
import { applyServerErrors } from '@macrulez/vue-form-schema'

const res = await fetch('/api/users', { method: 'POST', body: JSON.stringify(form.values.value) })
if (!res.ok) {
  const { formErrors } = applyServerErrors(form, await res.json(), { format: 'laravel' })
  if (formErrors.length) toast.error(formErrors[0]) // errors not tied to a specific field
}

Built-in formats:

'laravel'

{ message, errors: { field: ["msg", ...], "nested.field": [...] } }

'drf'

{ field: ["msg"], nested: { field: ["msg"] } } (flattened to dot-paths); non_field_errors / detail become formErrors.

'flat'

{ field: "msg" | ["msg", ...] } — the default; matches most hand-rolled APIs.

Or pass your own mapper for anything else: (raw) => ({ fieldErrors: {...}, formErrors: [...] }).

Field errors set this way behave like any other entry in errors — the next time that field validates client-side (on blur by default, or on every keystroke with validateOn: 'input'), it's recomputed from the schema's own validators and the server error is naturally replaced. submit() also fully recomputes errors, so a stale server error never survives into the next submit attempt.

applyServerErrors(form, raw, options?):

format

'laravel' | 'drf' | 'flat' | ((raw) => ...) · default: 'flat'

Built-in format name or a custom mapper.

touch

boolean · default: true

Mark affected fields as touched so errors show immediately.

merge

boolean · default: true

Merge into existing errors instead of replacing them.

normalizeServerErrors(raw, format?) runs the same mapping without touching a form, if you just want { fieldErrors, formErrors } yourself.

Persisted forms

ts
useForm({
  schema,
  persist: 'local', // or 'session'
  persistKey: 'checkout', // optional — defaults to a hash of field names
})

Values are restored from storage on onMounted. reset() clears the stored value. SSR-safe: the storage read is guarded by typeof window !== 'undefined'.