Appearance
Schema Contract Locking
When Faucet auto-generates REST APIs from your database schema, any schema change — a renamed column, a dropped field, a type change — silently becomes a breaking API change. Downstream consumers discover the breakage in production.
Schema Contract Locking solves this by snapshotting the database schema as the API contract. The API shape stays stable even when the underlying database drifts. You decide when to promote changes to the API.
The Problem
Consider this flow:
- Backend team adds a
userstable with columnsid,name,email - Faucet generates
GET /api/v1/mydb/usersreturning those 3 fields - Frontend team builds against this API, relying on the
emailfield - DBA renames
email→email_address - The API now returns
email_addressinstead ofemail— frontend breaks silently
With contract locking, step 5 never happens. The API continues serving the locked schema shape while Faucet detects the drift and alerts you.
Lock Modes
Each service has a schema_lock mode that controls how schema changes are handled:
| Mode | Behavior |
|---|---|
| none (default) | Live schema = live API. No protection. Changes pass through instantly. |
| auto | Additive changes (new columns) auto-promote. Breaking changes (drops, renames, type changes) are blocked until explicitly promoted. |
| strict | All schema changes are blocked. Every change requires explicit promotion via faucet db promote. |
Recommended Mode
Auto mode is the best default for most teams. It gives you the instant-API experience for additive changes while protecting against breaking changes.
Quick Start
Lock a Service (CLI)
bash
# Set auto mode — locks all existing tables automatically
faucet db lock mydb
# Or set strict mode
faucet db lock mydb --mode strictLock a Service (Admin UI)
- Go to Schema Explorer in the admin panel
- Select your service from the dropdown
- Change Schema Lock from "None" to "Auto" or "Strict"
- All tables are locked automatically
Lock a Service (API)
bash
# Set the lock mode
curl -X PUT http://localhost:8080/api/v1/system/contract/mydb/mode \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"mode": "auto"}'
# Or lock a specific table
curl -X POST http://localhost:8080/api/v1/system/contract/mydb/users \
-H "Authorization: Bearer $TOKEN"How It Works
Contract Snapshots
When you lock a table, Faucet snapshots the current schema — column names, types, nullability, primary keys, foreign keys — and stores it as the contract. This snapshot becomes the source of truth for the API shape.
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Database │────▶│ Contract │────▶│ REST API │
│ (live) │ │ (snapshot) │ │ (stable) │
└─────────────┘ └──────────────┘ └─────────────┘
│ │
│ drift check │
└───────────────────┘Drift Detection
Faucet continuously compares the live database schema against the locked contract. Changes are classified into two categories:
Additive changes (safe):
- New column added
- Column changed from NOT NULL → nullable
Breaking changes (dangerous):
- Column removed
- Column type changed
- Column changed from nullable → NOT NULL
- Column renamed (detected as remove + add)
- Table dropped
Auto Mode Behavior
In auto mode:
- Additive changes are automatically promoted — the contract updates to include new columns
- Breaking changes are blocked — DDL operations that would cause breaking changes are rejected with HTTP 409
- The API always reflects the latest additive changes while protecting against breaking ones
Strict Mode Behavior
In strict mode:
- All DDL operations are blocked on locked tables
- The API shape is completely frozen
- Every change requires explicit promotion
OpenAPI Spec Stability
When schema locking is enabled, the OpenAPI spec uses the locked contract schema instead of the live database schema. This means:
- Downloaded OpenAPI specs are stable across database changes
- Code generation tools produce consistent client code
- CI/CD pipelines can diff OpenAPI specs to detect API changes
Drift Detection
Check Drift (CLI)
bash
# Check all tables in a service
faucet db diff mydb
# Example output:
# Service: mydb
# Table: users
# ⚠ ADDITIVE column_added: Column "bio" was added to table "users"
# Table: posts
# ✗ BREAKING column_removed: Column "body" was removed from table "posts"
# ⚠ ADDITIVE column_added: Column "content" was added to table "posts"
# Check a specific table
faucet db diff mydb --table users
# JSON output for CI
faucet db diff mydb --jsonCheck Drift (Admin UI)
The Schema Explorer shows drift with color-coded indicators:
| Indicator | Meaning |
|---|---|
| Green dot | Locked, no drift |
| Yellow dot | Additive drift (new columns) |
| Red pulsing dot | Breaking drift detected |
Click a table with drift to see the detailed drift report showing each change categorized as BREAKING or ADDITIVE.
Check Drift (API)
bash
# Get drift report for all locked tables
curl http://localhost:8080/api/v1/system/contract/mydb/diff \
-H "Authorization: Bearer $TOKEN"
# Check a specific table with live drift comparison
curl "http://localhost:8080/api/v1/system/contract/mydb/users?check=true" \
-H "Authorization: Bearer $TOKEN"The X-Schema-Drift response header is also set on schema endpoints:
X-Schema-Drift: none— no driftX-Schema-Drift: additive— safe changes detectedX-Schema-Drift: breaking— breaking changes detected
Promoting Changes
When you're ready to accept schema changes into the API contract, use the promote command:
Promote (CLI)
bash
# Promote a specific table
faucet db promote mydb --table users
# Promote all tables
faucet db promote mydb --allPromote (Admin UI)
- In Schema Explorer, click a table with drift
- Click the Promote button in the table header
- The contract updates to match the live schema
Promote (API)
bash
curl -X POST http://localhost:8080/api/v1/system/contract/mydb/users/promote \
-H "Authorization: Bearer $TOKEN"Unlocking
Unlock (CLI)
bash
# Unlock a specific table
faucet db unlock mydb --table users
# Unlock all tables in a service
faucet db unlock mydbUnlock (Admin UI)
- Click a locked table in Schema Explorer
- Click the Unlock button
Unlock (API)
bash
# Unlock a specific table
curl -X DELETE http://localhost:8080/api/v1/system/contract/mydb/users \
-H "Authorization: Bearer $TOKEN"
# Unlock all tables in a service
curl -X DELETE http://localhost:8080/api/v1/system/contract/mydb \
-H "Authorization: Bearer $TOKEN"CI/CD Integration
Schema locking is designed to integrate with CI/CD pipelines:
Drift Check in CI
Add a drift check step to your pipeline to catch breaking changes before deployment:
yaml
# GitHub Actions example
- name: Check schema drift
run: |
DRIFT=$(curl -s http://faucet:8080/api/v1/system/contract/mydb/diff \
-H "Authorization: Bearer ${{ secrets.FAUCET_API_KEY }}")
if echo "$DRIFT" | jq -e '.has_breaking' | grep -q true; then
echo "::error::Breaking schema changes detected!"
echo "$DRIFT" | jq '.tables[] | select(.has_breaking) | .items[]'
exit 1
fiOpenAPI Diff in CI
Compare OpenAPI specs between releases to detect API changes:
yaml
- name: Check OpenAPI changes
run: |
curl -s http://faucet:8080/openapi.json > current-spec.json
diff previous-spec.json current-spec.json || {
echo "::warning::OpenAPI spec has changed"
}API Reference
Endpoints
| Method | Path | Description |
|---|---|---|
PUT | /api/v1/system/contract/{service}/mode | Set lock mode (none/auto/strict) |
POST | /api/v1/system/contract/{service} | Lock all tables in service |
GET | /api/v1/system/contract/{service} | List all contracts |
DELETE | /api/v1/system/contract/{service} | Unlock all tables |
GET | /api/v1/system/contract/{service}/diff | Drift report for all tables |
POST | /api/v1/system/contract/{service}/{table} | Lock a single table |
GET | /api/v1/system/contract/{service}/{table} | Get contract (add ?check=true for drift) |
DELETE | /api/v1/system/contract/{service}/{table} | Unlock a single table |
POST | /api/v1/system/contract/{service}/{table}/promote | Promote contract to live schema |
CLI Commands
faucet db lock <service> [--table <name>] [--mode auto|strict]
faucet db unlock <service> [--table <name>]
faucet db diff <service> [--table <name>] [--json]
faucet db promote <service> --table <name> | --allBest Practices
- Start with auto mode — it provides the best balance of protection and convenience
- Check drift in CI — add
faucet db diff --jsonto your CI pipeline to catch breaking changes early - Promote intentionally — review drift reports before promoting, especially for breaking changes
- Lock early — enable locking as soon as downstream consumers start depending on your API
- Use OpenAPI specs — with locking enabled, the OpenAPI spec is stable and safe for code generation