Override APIs Locally
Overview
This guide explains how to quickly override specific API endpoints at a granular level when developing locally with sandboxes. This approach allows you to test a single API change against your local code while keeping everything else running on the stable cluster baseline. No complex YAML configuration or service mesh expertise required.
API-level sandboxing enables you to override individual API endpoints surgically, not entire services - while still relying on the sandbox or the baseline to satisfy other endpoints and dependencies.
This feature requires Signadot CLI v1.3.0+ and Signadot Operator v1.2.0+ on your cluster.
Prerequisites
- An active cluster connection with
signadot local connect - An existing sandbox (can contain fork, virtual, or local workloads)
- Local code that implements a modified or new API endpoint you want to test
Use virtual workloads when you want to keep baseline service behavior but override specific API calls locally. Virtual workloads point to the stable baseline service rather than creating separate service copies.
Steps
1. Connect Local Code with Override Middleware
Use the signadot local override command to connect your local code to the sandbox workload:
signadot local override \
--sandbox pr-263-location \
--workload location \
--workload-port 8081 \
--with localhost:8081
This command:
- Creates a middleware that intercepts requests to the specified workload
- Routes requests to your local process first (running on
localhost:8081) - Falls back to the cluster baseline automatically when needed
- Works for both HTTP and gRPC traffic
2. Implement Selective Override Logic
In your local code, use the sd-override response header to control which requests are overridden:
// Local development server (running on localhost:8081)
const express = require('express');
const app = express();
app.use(express.json());
const LOCATIONS_DATA = [
{ id: 1, name: "Dog My Home", coordinates: "231,773" },
{ id: 123, name: "Lion Rachel's Floral Designs", coordinates: "115,277" },
{ id: 392, name: "Bear Trom Chocolatier", coordinates: "577,322" },
{ id: 567, name: "Eagle Amazing Coffee Roasters", coordinates: "211,653" },
{ id: 731, name: "Tiger Japanese Desserts", coordinates: "728,326" }
];
// Override specific endpoint
app.get('/locations', (req, res) => {
// Your new implementation with modified data
res.set('sd-override', 'true');
res.json(LOCATIONS_DATA);
});
// Let other endpoints fall through to baseline
app.use((req, res) => {
// Don't set sd-override header
// Middleware will automatically route to baseline cluster service
res.status(404).end();
});
const port = process.env.PORT || 8081;
app.listen(port, () => {
console.log(`Local override server running on port ${port}`);
});
How It Works
The override middleware intelligently routes traffic based on the sd-override header:
- Request arrives → Middleware sends it to your local process first
- Local process responds → Middleware checks for
sd-overrideheader- If
sd-override: true→ Your local response is returned to the caller - If
sd-overrideis absent/false → Request is forwarded to the sandbox workload, and its response is returned to the caller
- If
- Automatic fallback → If your local service is unavailable, requests automatically fall through to the sandbox workload
This means you only need to implement the specific APIs you're changing. Everything else automatically uses the sandbox workload.
Managing Overrides
Listing Active Overrides
View all active traffic overrides:
signadot local override list
Removing Overrides
Delete a specific traffic override:
signadot local override delete <name> --sandbox <sandbox-name>
When you terminate an override session (Ctrl+C), the override is automatically removed from the sandbox.
Advanced Override Patterns
Using --except-status for Fallthrough
The --except-status flag inverts the override behavior. Instead of requiring sd-override: true to use your local response, ALL requests go to your local service EXCEPT when you return specific status codes:
signadot local override \
--sandbox pr-263-location \
--workload location \
--workload-port 8081 \
--with localhost:8081 \
--except-status 404,503
With this configuration:
app.get('/api/v1/orders/:id', (req, res) => {
// Only implement the specific case you're testing
if (req.params.id === '12345') {
// Your new implementation - this response will be used
res.json({
id: '12345',
status: 'delivered',
tracking_enabled: true
});
return;
}
// For all other cases, return 404
// This will fall through to the baseline cluster service
res.status(404).end();
});
Using Virtual Workloads for Single API Testing
Virtual workloads are ideal when you want to override a single API endpoint while keeping all other behavior identical to the baseline. Since virtual workloads point directly to the baseline service (rather than creating a fork), they incur near-zero cost while still allowing traffic routing through your sandbox.
Combined with API overrides, this enables you to:
- Implement only the specific API endpoint you're changing
- Let all other requests route to the baseline service automatically
- Test your change against real dependencies without deploying anything to the cluster
- Avoid the overhead of forking entire services
Example workflow:
name: "test-payment-api"
spec:
cluster: "staging-cluster"
description: "Testing new payment API endpoint"
virtual:
- name: "backend"
workload:
kind: Deployment
namespace: "backend"
name: "payment-service"
Then override just the endpoint you're testing:
// Local service - only implement what you're changing
app.post('/api/v1/payments/process', (req, res) => {
// Your new payment processing logic
res.set('sd-override', 'true');
res.json({
transaction_id: 'txn_new_12345',
status: 'pending',
fraud_check_enabled: true // New feature being tested
});
});
// All other endpoints fall through to baseline
app.use((req, res) => {
res.status(404).end();
});
This approach gives you maximum flexibility with minimum infrastructure overhead.
Common Use Cases
- Testing a single API endpoint change: Create a sandbox with a virtual workload, override only the endpoint you're modifying, and test against real dependencies
- Simulating error conditions: Override specific endpoints to return errors or timeouts while letting normal traffic flow to baseline
- Developing against unstable services: Mock unreliable dependencies locally while the rest of the system uses in-cluster dependencies
Conclusion
API overrides let you test individual endpoint changes against real dependencies without modifying entire services. Use the sd-override header or --except-status flag to control which requests your local code handles. Combine with virtual workloads for near-zero cost testing.
See Also
- CLI Reference: signadot local override - Complete reference for the override command
- Virtual Workloads - Learn more about virtual workloads
- Set up Local Sandboxes - Complete guide to local development workflows