React
La validazione lato server è obbligatoria
La validazione lato client risponde subito, quella lato server decide: chiunque può inviare una richiesta senza il form, quindi ogni campo va ricontrollato.
In sintesi
- Il client può essere aggirato: chiunque può inviare il corpo della richiesta senza aprire il form.
- Uno schema Zod condiviso evita di riscrivere le stesse regole nel browser e nella rotta.
- Unicità e limiti per piano restano vincoli del database, non dello schema.
La validazione lato client serve a rispondere subito, quella lato server è l'unica che decide: chiunque può inviare una richiesta senza passare dal form.
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
- Nessun contesto di form: il server legge il corpo della richiesta, non il componente, quindi ogni campo va nominato e controllato.
- Header falsificabili: un'intestazione che sembra arrivare dal browser può essere stata scritta a mano.
- Richieste doppie: due invii identici arrivano insieme e il secondo non deve creare un doppione.
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.
Domande frequenti
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.