Skip to main content

Import

import { zodAdapter, valibotAdapter } from "bytekit/schema-adapter";

What they do

Schema adapters wrap external validation libraries into a SchemaAdapter<T> interface so you can pass them to ApiClient’s validateResponse option. The client calls adapter.parse(data) after every successful response — if parsing fails, the error propagates immediately.

SchemaAdapter<T>

interface SchemaAdapter<T> {
  parse: (data: unknown) => T;
}
Any object that satisfies this interface works as a response validator. zodAdapter and valibotAdapter are convenience wrappers for the two most popular schema libraries.

zodAdapter

function zodAdapter<T>(schema: { parse: (data: unknown) => T }): SchemaAdapter<T>;
Wraps a Zod schema. Since Zod schemas already expose a parse method, you can also pass a Zod schema directly — the adapter simply adds type safety.
ParameterTypeDescription
schemaZod schema with .parse()Any Zod schema object.

Zod example

import { ApiClient } from "bytekit/api-client";
import { zodAdapter } from "bytekit/schema-adapter";
import { z } from "zod";

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

type User = z.infer<typeof UserSchema>;

const api = new ApiClient({ baseUrl: "https://api.example.com" });

const user = await api.get<User>("/users/1", {
  validateResponse: zodAdapter(UserSchema),
});
// user is fully typed and runtime-validated

valibotAdapter

function valibotAdapter<T>(
  schema: unknown,
  parseFn: (schema: unknown, data: unknown) => T,
): SchemaAdapter<T>;
Wraps a Valibot schema and its parse function. Unlike Zod, Valibot separates the schema definition from the parse function, so both must be provided.
ParameterTypeDescription
schemaValibot schemaThe schema definition.
parseFn(schema, data) => TValibot’s parse function.

Valibot example

import { ApiClient } from "bytekit/api-client";
import { valibotAdapter } from "bytekit/schema-adapter";
import { object, string, number, parse } from "valibot";

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

const api = new ApiClient({ baseUrl: "https://api.example.com" });

const user = await api.get("/users/1", {
  validateResponse: valibotAdapter(UserSchema, parse),
});

Type guard

import { isSchemaAdapter } from "bytekit/schema-adapter";

if (isSchemaAdapter(maybeAdapter)) {
  const parsed = maybeAdapter.parse(rawData);
}
isSchemaAdapter(obj) returns true if the object has a parse function — useful when you accept both ValidationSchema and SchemaAdapter in generic code.

Comparison

  • You already use Zod in your project
  • You want .parse() + .safeParse() error messages
  • You need transforms (.transform(), .default(), .refine())
  • You prefer Valibot’s tree-shakeable, functional API
  • You want a smaller bundle footprint for validation
  • You want zero external dependencies
  • You only need structural type checks and simple constraints
  • See ResponseValidator
Schema adapters are optional. If you don’t pass validateResponse, ApiClient returns the raw parsed JSON without validation.