Skip to content
Zap Studio
fetch
Esc
navigateopen⌘Jpreview
On this page

Validation

Validate response bodies with Zod, Valibot, ArkType, or any other Standard Schema-compatible validator.

Response validation works with any library that implements Standard Schema. fetch validates responses through validation, so any Standard Schema-compatible validator can be used.

Validation Flow

When a schema is provided:

  1. The HTTP request is executed.
  2. If the response is not ok and throwOnFetchError is true (the default), a FetchError is thrown before any parsing.
  3. The response body is read with response.json().
  4. The parsed value is validated against the provided Standard Schema.
  5. The validated value is returned, or validation issues are surfaced.
import { api } from "@zap-studio/fetch";
import { z } from "zod";

const UserSchema = z.object({ id: z.number(), name: z.string() });

const user = await api.get("https://api.example.com/users/1", UserSchema);

Supported Validators

Any validator that implements Standard Schema works — the schema is passed straight through, so transforms, defaults, and refinements behave exactly as the library defines them.

import { z } from "zod";

const UserSchema = z.object({
  id: z.number(),
  name: z.string(),
});
import * as v from "valibot";

const UserSchema = v.object({
  id: v.number(),
  name: v.string(),
});
import { type } from "arktype";

const UserSchema = type({
  id: "number",
  name: "string",
});

Throwing Mode

By default (throwOnValidationError: true), a ValidationError is thrown when the response does not match the schema. Import it from validation.

import { api } from "@zap-studio/fetch";
import { ValidationError } from "@zap-studio/validation";
import { z } from "zod";

const UserSchema = z.object({ id: z.number(), name: z.string() });

try {
  const user = await api.get("https://api.example.com/users/1", UserSchema);
  console.log(user);
} catch (error) {
  if (error instanceof ValidationError) {
    console.error(error.issues);
  } else {
    throw error;
  }
}

@zap-studio/validation is a runtime dependency of @zap-studio/fetch, but install it explicitly if you import from it directly.

Result Mode

Set throwOnValidationError: false to receive the Standard Schema result object — { value } on success, { issues } on failure.

import { api } from "@zap-studio/fetch";
import { z } from "zod";

const UserSchema = z.object({ id: z.number(), name: z.string() });

const result = await api.get("https://api.example.com/users/1", UserSchema, {
  throwOnValidationError: false,
});

if (result.issues) {
  console.error(result.issues);
} else {
  console.log(result.value);
}

Validating Request Bodies

For request-body validation, validate the payload yourself before passing it to json.

import { api } from "@zap-studio/fetch";
import { standardValidate } from "@zap-studio/validation";
import { z } from "zod";

const CreateUserInputSchema = z.object({ name: z.string() });
const UserSchema = z.object({ id: z.number(), name: z.string() });

const rawInput: unknown = { name: "Ada" };

const input = await standardValidate(rawInput, CreateUserInputSchema, {
  throwOnError: true,
});

const user = await api.post("https://api.example.com/users", UserSchema, {
  json: input,
});

Standalone Validation

For validation outside HTTP requests, use validation directly. It also exports the StandardSchemaV1 type when you need to type schema parameters yourself.

import { standardValidate } from "@zap-studio/validation";
import type { StandardSchemaV1 } from "@zap-studio/validation";
import { z } from "zod";

const UserSchema = z.object({ id: z.number(), name: z.string() });

const input: unknown = { id: 1, name: "Ada" };

const user = await standardValidate(input, UserSchema, {
  throwOnError: true,
});

Last updated on September 15, 2026

Was this page helpful?