# How to Validate API Requests with Zod Schemas in OmniRoute

> Learn how OmniRoute uses Zod schemas for robust API request validation. Discover two complementary layers for strict envelope and lightweight inline checks, ensuring uniform 400 error responses for better API integrity.

- Repository: [Diego Rodrigues de Sa e Souza/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- Tags: how-to-guide
- Published: 2026-08-16

---

**OmniRoute validates incoming API payloads using two complementary Zod-based layers: a generic `validatedJsonBody` helper for strict envelope validation and lightweight inline schemas for hot-path shape checks, both producing uniform `400` error responses.**

The OmniRoute API framework, developed by Diego Souza, implements a dual-layer validation strategy using **Zod schemas** to ensure type-safe request handling while maintaining performance on critical endpoints. This approach allows developers to choose between comprehensive validation through reusable helpers or minimal overhead through route-level shape checks.

## Generic Envelope Validation with validatedJsonBody

The foundation of OmniRoute's request validation resides in [[`src/shared/validation/helpers.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/validation/helpers.ts)](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.50/src/shared/validation/helpers.ts). The `validatedJsonBody(request, schema)` function provides a standardized way to parse and validate JSON payloads across all API routes.

This helper performs four key operations:

- **Single-pass parsing**: Reads the request body once via `await request.json()`.
- **JSON syntax validation**: Returns an immediate `400` response with "Invalid JSON body" if parsing fails.
- **Zod schema execution**: Delegates to `validateBody(schema, raw)`, which runs `schema.safeParse()`.
- **Structured error formatting**: On Zod failure, builds an error payload enumerating each failed field with its path and message.

Routes import this helper to eliminate duplicate error-handling code. The function returns either `{ success: true, data: T }` with the parsed and typed payload, or `{ success: false, response: NextResponse }` containing a ready-to-send `400` error.

### Usage Example

```typescript
import { z } from "zod";
import { validatedJsonBody } from "@/shared/validation/helpers";

const updateComboSchema = z.object({
  name:      z.string().min(1),
  maxTokens: z.number().int().positive(),
});

export async function POST(request: Request) {
  const result = await validatedJsonBody(request, updateComboSchema);
  if (!result.success) return result.response;
  const body = result.data; // Type-safe inferred from schema
  // …process validated payload…
}

```

*Source:* [`src/app/api/v1/providers/[provider]/models/route.ts`](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.50/src/app/api/v1/providers/[provider]/models/route.ts)

## Route-Level Shape Validation for Hot Paths

Performance-critical endpoints employ an alternative pattern: **inline Zod schemas** that validate only the minimal shape required before delegating to deeper handlers. This avoids the overhead of full schema validation on high-traffic routes.

The [[`src/app/api/v1/chat/completions/route.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/app/api/v1/chat/completions/route.ts)](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.50/src/app/app/api/v1/chat/completions/route.ts) demonstrates this approach with the `chatCompletionsRouteShapeSchema`:

```typescript
const chatCompletionsRouteShapeSchema = z
  .object({
    model:    z.string().nullable().optional(),
    messages: z.array(z.unknown()).optional(),
  })
  .passthrough();

```

The `.passthrough()` modifier allows additional properties to flow through to downstream validation, making this a **guardrail rather than a gatekeeper**.

### Implementation Pattern

```typescript
if (isRecord(parsedBody)) {
  const shapeCheck = chatCompletionsRouteShapeSchema.safeParse(parsedBody);
  if (!shapeCheck.success) {
    const issue = shapeCheck.error.issues[0];
    const field = issue?.path?.length ? issue.path.join(".") : "body";
    return finishAdmission(
      errorResponse(400, `${field}: ${issue?.message ?? "Invalid request"}`)
    );
  }
}

```

After this lightweight check succeeds, the unmodified payload proceeds to `handleChat()`, which performs comprehensive model-level validation.

## How the Two Validation Layers Compare

| Layer | Location | Validation Scope | Best For |
|-------|----------|------------------|----------|
| **Envelope** | [`helpers.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/helpers.ts) (`validatedJsonBody`) | JSON parsing + full Zod schema | Standard routes needing strict contracts (e.g., `/v1/models`, `/v1/registered-keys`) |
| **Shape** | Inline route files | Minimal object shape | High-traffic endpoints where double-parsing must be avoided |

Both layers converge on the identical error envelope structure: `{ error: { message, details } }`. This consistency ensures client SDKs parse failures uniformly regardless of which validation layer triggered the rejection.

## Reusable Schema Library

Beyond one-off route schemas, OmniRoute maintains a centralized collection in [`src/shared/validation/schemas/`](https://github.com/diegosouzapw/OmniRoute/tree/release/v3.8.50/src/shared/validation/schemas). This directory houses Zod definitions for:

- **Settings** — application configuration objects
- **Routing rules** — load balancing and provider selection logic
- **Provider definitions** — third-party API credential and endpoint schemas

These reusable schemas are imported across the codebase, preventing schema drift and enabling single-source-of-truth updates.

## Testing the Validation Pipeline

The framework includes comprehensive test coverage in [[`tests/unit/api/validated-json-body.test.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/tests/unit/api/validated-json-body.test.ts)](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.50/tests/unit/api/validated-json-body.test.ts). This suite verifies:

- Malformed JSON detection
- Field-level Zod failure reporting
- Empty body handling
- Type inference correctness

Tests ensure the `validatedJsonBody` helper behaves predictably across edge cases, providing confidence for API consumers.

## Summary

- **OmniRoute request validation** centers on Zod schemas applied through two complementary patterns.
- **`validatedJsonBody`** in [`src/shared/validation/helpers.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/validation/helpers.ts) provides full-featured, reusable validation with automatic error response generation.
- **Inline shape schemas** offer minimal-overhead guardrails for performance-critical routes like chat completions.
- **Unified error formatting** guarantees consistent client experiences across all validation paths.
- **Centralized schema library** in `src/shared/validation/schemas/` promotes reuse and maintainability.

## Frequently Asked Questions

### What happens when Zod validation fails in OmniRoute?

The framework returns a `400 Bad Request` response with a structured error object containing `message` and `details` arrays. Each detail includes the failing field path and its specific validation message. Both `validatedJsonBody` and inline shape checks produce this identical format.

### Can I use my own Zod schemas with OmniRoute's validation helpers?

Yes. The `validatedJsonBody` function accepts any `z.ZodSchema<T>` as its second parameter. You define your schema using standard Zod methods, import it into your route handler, and pass it directly. The helper handles all parsing, validation, and error formatting transparently.

### Why does the chat completions route use `.passthrough()` in its schema?

The `.passthrough()` modifier allows the schema to validate required fields (model, messages) without stripping unknown properties. This permits the downstream `handleChat()` function to receive the complete original payload—including fields the shape schema doesn't explicitly recognize—while still catching malformed requests early.

### Where should I place reusable Zod schemas in an OmniRoute project?

Place domain-specific schemas in `src/shared/validation/schemas/` following the existing convention. This central location makes schemas discoverable for import across routes, reduces duplication, and enables atomic updates when API contracts evolve.