# Server-side validation is mandatory

Client-side validation answers fast, server-side validation decides: anyone can send a request without the form, so every field is rechecked.

> Page: https://ui.eneawork.it/blog/validazione-lato-server-obbligatoria
> Markdown: https://ui.eneawork.it/blog/validazione-lato-server-obbligatoria.md

*2026-11-01*

La validazione lato client serve a rispondere subito, quella lato server è l'unica che decide: chiunque può inviare una richiesta senza passare dal form.

Il catalogo EneUI conta 111.985 componenti, 1.556 blocchi e 12.808 icone da 1.472 librerie, letti da /api/stats il 1 novembre 2026. La cifra viene da una query all'endpoint, non da una stima: conta i record pubblicati, non la qualità dei componenti.

## Chi può saltare il form

Un form nel browser è un client come un altro: si può spegnere il JavaScript, cambiare un attributo, scrivere un fetch a mano o ripetere la richiesta dieci volte. Il server riceve byte, quindi deve controllare ogni campo che usa, anche quando il client ha già detto che va bene.

## Uno schema, due esecuzioni

import { z } from "zod"; const Signup = z.object({ email: z.string().email(), password: z.string().min(12), }); // Nel browser: feedback immediato. Signup.safeParse(values); // Sul server: stessa funzione, stessa verità. const parsed = Signup.safeParse(await request.json()); if (!parsed.success) { return Response.json({ errors: parsed.error.flatten() }, { status: 422 }); }

Zod, distribuito con licenza MIT, restituisce un risultato tipizzato invece di lanciare: lo stesso schema gira nel browser e nella rotta, e il messaggio d'errore non va riscritto due volte.

## Cosa il server non può sapere

## La prova, in un comando

curl -i -X POST http://localhost:3000/api/signup \ -H "Content-Type: application/json" \ -d '{"email":"nope","password":"1"}'

Il comando salta il form e mostra la risposta grezza: se la rotta accetta quel corpo, il problema è nel server, non nel client.

## Record vivi nel catalogo

Tre form in cui la validazione server conta: sign-in-form, auth-form e form-layout-01. Per sfogliare per categoria parti da 111.985 componenti.

## La limitazione

Lo schema condiviso controlla la forma, non le regole di business: unicità dell'email, password compromesse e limiti di piano restano query e vincoli nel database. Due richieste contemporanee passano lo schema e collidono sull'indice unico, quindi il vincolo va scritto anche lì.

## Dove continuare

Il flusso completo è in validazione con Server Actions; il confronto fra le librerie misurate è in librerie form React; la scelta fra azione server e API è in Server Actions vs API.

## FAQ

### La validazione lato client è inutile?

No, serve a dare un errore prima del viaggio di rete. Non è una difesa: il server deve ripetere ogni controllo che usa.

### Devo duplicare le regole nel server?

No, conviene uno schema unico importato dai due lati. Se le due copie divergono, la differenza è un bug.

### Che codice di stato torna con un errore di validazione?

422 di solito. Il 400 resta per una richiesta malformata, il 422 per un corpo leggibile ma non valido.

### Come si fermano i doppi invii?

Con una chiave di idempotenza per richiesta e un indice unico nel database, non con un pulsante disabilitato.

### Zod è obbligatorio?

No. Qualsiasi schema condiviso va bene; Zod è distribuito con licenza MIT e restituisce un risultato tipizzato.
