How to Validate API Requests with Zod Schemas in OmniRoute

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/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

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

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/release/v3.8.50/src/app/app/api/v1/chat/completions/route.ts) demonstrates this approach with the chatCompletionsRouteShapeSchema:

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

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 (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/. 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/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 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →