Skip to main content

Validation Modes

What are Validation Modes?

When you add CVT validation middleware to your API server, you need to decide what happens when a request or response doesn't match your OpenAPI schema. Should invalid requests be rejected? Should violations be logged? Or should validation run silently in the background?

Validation modes control this behavior. They let you start with zero-risk observability and gradually move toward full contract enforcement as you gain confidence.

Adding contract validation to a production API can be risky. You might discover that:

  • Your OpenAPI spec doesn't match your actual implementation
  • Some clients send requests that don't match the documented format
  • Edge cases in your responses weren't captured in the schema

Validation modes let you deploy safely by starting in observation mode, fixing issues, then enabling enforcement—without breaking existing clients.

Mode Reference

ModeRequest ViolationResponse ViolationMetricsUse Case
strictReject with 400 Bad RequestLog error (response already sent)RecordedProduction enforcement after rollout
warnLog warning, continue processingLog warning, continueRecordedGradual rollout, monitoring impact
shadowSilent (no logging)Silent (no logging)RecordedInitial deployment, metrics-only analysis

Mode Behavior Details

Strict Mode

Request → Validate → Invalid? → Return 400 (handler never executes)
→ Valid? → Execute handler → Validate response → Log if invalid
  • Request violations: Immediately rejected with 400 Bad Request and error details
  • Response violations: Logged as errors but response is still sent (can't unsend)
  • Best for: Production APIs after you've validated with warn/shadow modes

Warn Mode

Request → Validate → Log if invalid → Execute handler → Validate response → Log if invalid
  • Request violations: Logged as warnings, request continues to handler
  • Response violations: Logged as warnings, response is sent normally
  • Best for: Transitioning from shadow to strict, identifying issues without breaking clients

Shadow Mode

Request → Validate → Execute handler → Validate response
↓ ↓
Record metrics Record metrics
(no logging) (no logging)
  • Request violations: Only recorded in metrics, no logs, no impact
  • Response violations: Only recorded in metrics, no logs, no impact
  • Best for: Initial deployment to measure contract compliance without any risk
┌─────────────────────────────────────────────────────────────────────────────┐
│ Production Rollout Phases │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Phase 1 Phase 2 Phase 3 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ SHADOW │ ──────► │ WARN │ ──────► │ STRICT │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ • Deploy middleware • Enable logging • Full enforcement │
│ • Monitor metrics • Review violations • Reject invalid requests │
│ • Zero risk • Fix issues found • Contract is enforced │
│ • Measure baseline • No client impact • Clients must comply │
│ │
└─────────────────────────────────────────────────────────────────────────────┘

Step-by-step:

  1. Deploy with shadow — Add middleware to production with zero risk. Monitor the cvt_validation_errors_total metric to understand your baseline.

  2. Analyze metrics — Use Grafana dashboards to identify which endpoints have the most violations. Common issues: missing required fields, wrong types, undocumented endpoints.

  3. Switch to warn — Enable logging to get detailed error messages. Review logs to understand exactly what's failing and why.

  4. Fix violations — Either update your OpenAPI spec to match reality, or fix client/server code to match the spec. This is where you decide what the contract should be.

  5. Switch to strict — Full enforcement. Invalid requests are rejected. Your API contract is now enforced.

Mode Configuration by SDK

Each SDK uses language-appropriate naming conventions:

SDKStrictWarnShadow
Node.jsmode: "strict"mode: "warn"mode: "shadow"
PythonValidationMode.STRICTValidationMode.WARNValidationMode.SHADOW
Goproducer.ModeStrictproducer.ModeWarnproducer.ModeShadow
JavaValidationMode.STRICTValidationMode.WARNValidationMode.SHADOW
import { createExpressMiddleware } from "@sahina/cvt-sdk/producer";

app.use(
createExpressMiddleware({
schemaId: "petstore",
validator,
mode: "strict", // or "warn" or "shadow"
}),
);

Metrics Emitted

All modes emit Prometheus metrics for monitoring:

MetricDescription
cvt_validations_totalTotal validations by schema, method, result
cvt_validation_errors_totalValidation failures by error category
cvt_validation_duration_secondsValidation latency histogram by schema and method

Use these metrics to:

  • Track contract compliance over time
  • Identify problematic endpoints before enabling strict mode
  • Monitor the impact of API changes
  • Alert on sudden increases in validation failures

Response Validation Behavior

Important: Response validation can only log, never block.

Client Request


Validate Request ─── Can reject (strict mode)


Your Handler


Send Response ─── Already sent to client!


Validate Response ─── Can only log (too late to block)

This is by design: by the time we validate the response, it's already been sent to the client. Response validation helps you detect implementation drift (where your code diverges from your spec) but can't prevent invalid responses from reaching clients.

To prevent invalid responses: Validate your response data before sending it, or use typed response builders that enforce the schema at compile time.