Validering av begäranden och typade JSON-svar med Zod
Parsa och validera begärandekroppar och frågeparametrar och returnera typade, välstrukturerade felsvar.
Validering av begäranden och typade JSON-svar med Zod är en gratis lektion i Next.js 15 fullstack (App Router + Server Actions) på CoddyKit. Detta är lektion 4 av 4. Du kan läsa vilka 3 lektioner som helst i den här lärvägen kostnadsfritt i sin helhet – därefter låser CoddyKit PRO upp alla lektioner, plus praktisk övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Den ingår i lärvägen för Next.js 15 fullstack (App Router + Server Actions), och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Next.js 15 fullstack (App Router + Server Actions) innehåller totalt 4 lektioner.
Varför validera i Edge?
I Next.js 15 Route Handlers (app/api/.../route.ts) är request-body:n helt enkelt typad JSON utan typinformation. TypeScript-typer försvinner vid körning, så en klient kan skicka vad som helst.
Zod låter dig beskriva den förväntade strukturen en gång och få både:
- En körningskontroll som avvisar felaktig indata.
- En statisk typ som härleds från schemat, så att handler-koden är fullständigt typad.
I den här lektionen bygger du en typad POST-handler som validerar body och query-parametrar och sedan returnerar rena, strukturerade JSON-fel.
Definiera ett schema
Börja med att deklarera den struktur du förväntar dig. Zod-scheman fungerar som den enda källan till sanning för både validering och typer.
Använd z.infer för att härleda en TypeScript-typ från schemat. Det finns ingen duplicering: ändra schemat, så uppdateras typen automatiskt.
import { z } from 'zod';
export const CreateUserSchema = z.object({
name: z.string().min(1, 'Name is required'),
email: z.string().email('Invalid email address'),
age: z.number().int().positive().optional(),
});
// Inferred type — fully typed, no duplication
export type CreateUserInput = z.infer<typeof CreateUserSchema>;Parsa request-body:n
Inuti en Route Handler läser du JSON med await request.json(). Omslut anropet med try/catch, eftersom felaktig JSON kastar ett undantag innan Zod ens körs.
Använd schema.safeParse() i stället för parse(). safeParse kastar aldrig ett undantag — den returnerar ett resultatobjekt som du kan förgrena logiken utifrån.
import { NextRequest, NextResponse } from 'next/server';
import { CreateUserSchema } from './schema';
export async function POST(request: NextRequest) {
let body: unknown;
try {
body = await request.json();
} catch {
return NextResponse.json(
{ error: 'Invalid JSON body' },
{ status: 400 },
);
}
const result = CreateUserSchema.safeParse(body);
// ...handle result
}safeParse: lyckat eller misslyckat
safeParse returnerar en diskriminerad union:
- Vid lyckat resultat:
{ success: true, data }, därdataär det typade och validerade värdet. - Vid misslyckat resultat:
{ success: false, error }, därerrorär ettZodError.
TypeScript begränsar typen efter att du har kontrollerat result.success, så result.data är bara åtkomligt i grenen för lyckat resultat.
const result = CreateUserSchema.safeParse(body);
if (!result.success) {
return NextResponse.json(
{ error: 'Validation failed', issues: result.error.issues },
{ status: 422 },
);
}
// result.data is now typed as CreateUserInput
const user = result.data;
console.log(user.email);Utforma ett användbart felsvar
Det fungerar att skriva ut det råa ZodError, men resultatet blir rörigt. Ett renare API returnerar en platt mappning från fält till meddelanden. Zods error.flatten() ger dig fieldErrors och formErrors, färdiga för klienten.
Välj en konsekvent status: 400 för indata som inte kan parsas och 422 (Unprocessable Entity) för välformad JSON som inte klarar valideringen.
if (!result.success) {
const { fieldErrors, formErrors } = result.error.flatten();
return NextResponse.json(
{
error: 'Validation failed',
fieldErrors, // { email: ['Invalid email address'] }
formErrors, // top-level errors
},
{ status: 422 },
);
}Validera query-parametrar
Query-parametrar kommer in som strängar via request.nextUrl.searchParams. Använd z.coerce för att konvertera och validera i ett enda steg — till exempel omvandla ?page=2 till ett faktiskt tal.
Ange standardvärden med .default() så att saknade parametrar inte får handlern att misslyckas.
import { z } from 'zod';
import { NextRequest, NextResponse } from 'next/server';
const QuerySchema = z.object({
page: z.coerce.number().int().min(1).default(1),
limit: z.coerce.number().int().min(1).max(100).default(20),
});
export async function GET(request: NextRequest) {
const params = Object.fromEntries(request.nextUrl.searchParams);
const result = QuerySchema.safeParse(params);
if (!result.success) {
return NextResponse.json(
{ error: 'Invalid query', fieldErrors: result.error.flatten().fieldErrors },
{ status: 400 },
);
}
const { page, limit } = result.data; // numbers, defaulted
return NextResponse.json({ page, limit });
}Typade JSON-svar
NextResponse.json() är generisk. Skicka med ett typargument för att låsa fast formen på nyttolasten vid lyckade svar, så att din handler och din klient förblir synkroniserade.
Definiera en gemensam svarstyp och återanvänd den både på servern och i frontendens fetch-anrop.
import { NextResponse } from 'next/server';
type UserResponse = {
id: string;
name: string;
email: string;
};
function ok(user: UserResponse) {
// The generic enforces the body matches UserResponse
return NextResponse.json<UserResponse>(user, { status: 201 });
}En återanvändbar valideringshjälpare
Det blir omständligt att upprepa parse-/förgreningslogiken i varje handler. Extrahera en liten hjälpare som validerar en body mot valfritt schema och returnerar ett typat resultat.
På så sätt kan varje Route Handler fokusera på affärslogik, medan formatet för felsvar centraliseras.
import { z } from 'zod';
import { NextResponse } from 'next/server';
export async function parseBody<T extends z.ZodTypeAny>(
request: Request,
schema: T,
): Promise<
| { ok: true; data: z.infer<T> }
| { ok: false; response: NextResponse }
> {
let raw: unknown;
try {
raw = await request.json();
} catch {
return { ok: false, response: NextResponse.json({ error: 'Invalid JSON' }, { status: 400 }) };
}
const result = schema.safeParse(raw);
if (!result.success) {
return {
ok: false,
response: NextResponse.json(
{ error: 'Validation failed', fieldErrors: result.error.flatten().fieldErrors },
{ status: 422 },
),
};
}
return { ok: true, data: result.data };
}Använda hjälparen i en handler
När parseBody finns på plats blir en handler kort och lättläst. Validera, returnera tidigt vid fel och arbeta sedan med fullt typade data.
Det här mönstret skalar: varje endpoint följer samma struktur, så felsvaren blir konsekventa i hela ditt API.
import { NextRequest } from 'next/server';
import { CreateUserSchema } from './schema';
import { parseBody } from '@/lib/parse-body';
import { NextResponse } from 'next/server';
export async function POST(request: NextRequest) {
const parsed = await parseBody(request, CreateUserSchema);
if (!parsed.ok) return parsed.response;
const { name, email } = parsed.data; // typed
const user = { id: crypto.randomUUID(), name, email };
return NextResponse.json(user, { status: 201 });
}Transformera och förfina
Zod kan göra mer än att avvisa — det kan normalisera. Använd .transform() för att omforma värden (trimma, konvertera till gemener) och .refine() för regler mellan fält som en kontroll av ett enskilt fält inte kan uttrycka.
Utgångstypen återspeglar transformationerna, så efterföljande kod ser de rensade uppgifterna.
import { z } from 'zod';
const SignupSchema = z
.object({
email: z.string().email().transform((s) => s.toLowerCase().trim()),
password: z.string().min(8),
confirm: z.string(),
})
.refine((d) => d.password === d.confirm, {
message: 'Passwords do not match',
path: ['confirm'],
});
type Signup = z.infer<typeof SignupSchema>;Valideringslogik som du faktiskt kan köra
Skala bort Next.js, så återstår idén om ren datavalidering. Här är ett fristående TypeScript-program som återspeglar samma parse- och förgreningsflöde med Zod, utan någon server.
Det visar både en giltig och en ogiltig nyttolast och skriver ut den strukturerade felkartan.
import { z } from 'zod';
const Schema = z.object({
name: z.string().min(1),
email: z.string().email(),
age: z.coerce.number().int().positive().optional(),
});
function validate(input: unknown) {
const result = Schema.safeParse(input);
if (!result.success) {
return { status: 422, body: { fieldErrors: result.error.flatten().fieldErrors } };
}
return { status: 201, body: result.data };
}
console.log(JSON.stringify(validate({ name: 'Ada', email: 'ada@example.com', age: '30' })));
console.log(JSON.stringify(validate({ name: '', email: 'nope' })));Snabbkontroll
Du skriver en POST Route Handler som validerar JSON-body:n med ett Zod-schema. Vilket tillvägagångssätt returnerar bäst ett typat, strukturerat felsvar utan att krascha vid ogiltiga indata?
Sammanfattning
Du har byggt en typad och validerad API-endpoint i Next.js 15:
- Schemat först: definiera ett Zod-schema och härled typen med
z.infer. - safeParse, inte parse: förgrena utifrån
result.successså att inget kastas. - Strukturerade fel: använd
error.flatten(); returnera 400 för ogiltig JSON och 422 för valideringsfel. - Frågeparametrar: konvertera strängar med
z.coerceoch ange standardvärden med.default(). - Typade svar:
NextResponse.json<T>()håller servern och klienten synkroniserade. - Återanvändning: en
parseBody-hjälpare centraliserar parse-/felmönstret i alla handlers.
Resultatet är ett edge-API som är säkert vid körning och fullt typat vid kompilering.
Lär dig TypeScript med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 22
- Lektioner
- 88
Vanliga frågor
Är lektionen ”Validering av begäranden och typade JSON-svar med Zod” gratis?
Ja – du kan läsa vilka 3 lektioner som helst i lärvägen Next.js 15 fullstack (App Router + Server Actions), inklusive ”Validering av begäranden och typade JSON-svar med Zod”, kostnadsfritt i sin helhet här på webben. Därefter låser CoddyKit PRO upp alla lektioner, plus interaktiv övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Kursen i Next.js 15 fullstack (App Router + Server Actions) innehåller totalt 4 lektioner.
Vad lär jag mig i ”Validering av begäranden och typade JSON-svar med Zod”?
Parsa och validera begärandekroppar och frågeparametrar och returnera typade, välstrukturerade felsvar. Ni övar på Next.js 15 fullstack (App Router + Server Actions) med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig Next.js 15 fullstack (App Router + Server Actions)?
Du behöver inga förkunskaper. Utbildningen i Next.js 15 fullstack (App Router + Server Actions) på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 4 av 4.
Hur lång tid tar lektionen ”Validering av begäranden och typade JSON-svar med Zod”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här Next.js 15 fullstack (App Router + Server Actions)-lektionen?
Ja. Varje Next.js 15 fullstack (App Router + Server Actions)-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- Utforma RESTful-routningshanterare med Web Request API
- Avvägningar mellan Node-runtime och Edge-runtime
- Strömmande svar och ReadableStream i hanterare
- Validering av begäranden och typade JSON-svar med Zod