Skip to content

Commit 16c8d72

Browse files
committed
Add blog post: API Retirement Done Right
Covers how Barbacane's spec-driven approach turns API retirement into a routine lifecycle operation, leveraging built-in deprecation headers, x-sunset support, and dedicated Prometheus metrics.
1 parent 7b602f6 commit 16c8d72

File tree

1 file changed

+286
-0
lines changed

1 file changed

+286
-0
lines changed
Lines changed: 286 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
---
2+
title: "API Retirement Done Right: How Spec-Driven Gateways Turn End-of-Life Into a Non-Event"
3+
description: "APIs are easy to launch and nearly impossible to kill. Explore how Barbacane's compiled, spec-driven approach turns API retirement from an organizational ordeal into a routine lifecycle operation."
4+
publishDate: 2026-03-03
5+
author: "Nicolas Dreno"
6+
tags: ["barbacane", "api-gateway", "api-lifecycle", "versioning", "openapi", "deprecation"]
7+
---
8+
9+
*APIs are easy to launch and nearly impossible to kill.*
10+
11+
Most API programs invest heavily in design, launch, and adoption. Far less attention is given to what happens years later, when early versions remain active long after their original purpose has faded. The result is predictable: APIs accumulate. v1 still runs alongside v2 and v3. Each version carries its own routing rules, authentication flows, rate limits, and schema quirks. Nobody is confident enough to turn anything off, because nobody knows who's still calling what.
12+
13+
This isn't a discipline problem. It's a visibility problem, amplified by tooling that was never designed to make retirement safe.
14+
15+
---
16+
17+
### The Long Tail of Legacy Versions
18+
19+
The original intent behind strict backward compatibility is sound. Breaking client integrations damages trust and disrupts revenue-generating workflows. So teams avoid removing endpoints, even when newer versions exist and migration guides have been published for months.
20+
21+
Over time, this creates real operational drag:
22+
23+
- **Expanded testing surface.** Every release must be validated against every active version. Three concurrent versions don't triple the effort, but they come close.
24+
- **Security exposure.** Legacy endpoints may use deprecated authentication schemes, outdated schemas, or pre-date current authorization policies. Each is a potential vulnerability that must still be monitored and patched.
25+
- **Incident complexity.** When something breaks, the investigation must account for historical behaviors across versions. "Which version was the client calling?" becomes the first question in every postmortem.
26+
- **Documentation burden.** Maintaining accurate docs for versions that nobody wants to support but nobody dares to remove.
27+
28+
The fundamental challenge is uncertainty. Organizations frequently lack clear visibility into who is still consuming older versions, how heavily, and whether those consumers have been notified about available upgrades.
29+
30+
---
31+
32+
### Why Traditional Gateways Make Retirement Harder
33+
34+
In a conventional gateway setup, the API specification and the gateway configuration are separate artifacts maintained by separate processes. This dual-source model, the [configuration drift problem](/blog/beyond-configuration-drift/) we've discussed before, makes retirement particularly painful.
35+
36+
Consider what it takes to retire `v1` of an API on a traditional gateway:
37+
38+
1. **Identify what's running.** Which routes belong to v1? Are they in the same config file as v2, or spread across multiple configurations? Are there routes that were added as hotfixes and never documented in any spec?
39+
2. **Determine who's calling.** Gateway logs might tell you about traffic patterns, but correlating log entries to specific consumer identities across versions requires additional telemetry that may or may not exist.
40+
3. **Coordinate the removal.** Delete routes from the gateway config. Update the spec (if it's still maintained). Remove documentation. Hope nothing was missed.
41+
4. **Verify nothing broke.** Because the config and spec are separate, removing something from one doesn't guarantee it's gone from the other. The gateway might still serve a route that was "retired" in the spec, or the spec might still document a route that was removed from the config.
42+
43+
At every step, the gap between specification and configuration creates ambiguity. And ambiguity is what makes retirement decisions stall. When you can't confidently answer "what exactly will change when we remove this?", the safe default is to do nothing.
44+
45+
---
46+
47+
### Lean on OpenAPI - Don't Reinvent
48+
49+
Barbacane's approach to API lifecycle is deliberately minimal: use what OpenAPI already gives you, and make the gateway enforce it. No custom lifecycle DSL. No retirement orchestration layer. Just standard fields, compiled into standard behavior.
50+
51+
This philosophy extends to versioning itself. Barbacane does not impose a versioning strategy. URL-path versioning (`/v1/users`, `/v2/users`), header-based content negotiation, or separate spec files per version - all work because the gateway routes what the spec declares. Versioning is a spec concern, not a gateway concern.
52+
53+
What Barbacane *does* add is enforcement. When you mark something as deprecated in your spec, the gateway acts on it. When you remove a route from the spec, it's gone from the gateway. There's no separate configuration layer where retired routes could linger.
54+
55+
---
56+
57+
### Deprecation: Built Into the Spec, Enforced by the Gateway
58+
59+
OpenAPI has a standard `deprecated` field on operations. Most tools treat it as documentation metadata. Barbacane treats it as a runtime directive.
60+
61+
```yaml
62+
paths:
63+
/v1/users:
64+
get:
65+
deprecated: true
66+
summary: List users (deprecated, use /v2/users)
67+
x-barbacane-dispatch:
68+
name: http-upstream
69+
config:
70+
url: "https://api.example.com"
71+
```
72+
73+
When a client calls a deprecated endpoint, Barbacane does three things automatically:
74+
75+
1. **Serves the request.** Deprecated does not mean removed. The endpoint still works, preserving backward compatibility during the migration window.
76+
77+
2. **Injects a `Deprecation: true` response header** per [draft-ietf-httpapi-deprecation-header](https://datatracker.ietf.org/doc/draft-ietf-httpapi-deprecation-header/). Well-behaved HTTP clients and API tooling surface this automatically.
78+
79+
3. **Increments a dedicated metric:** `barbacane_deprecated_route_requests_total`, labeled by method, path, and API name. This is the telemetry that makes retirement decisions data-driven.
80+
81+
No middleware to configure. No plugin to enable. The `deprecated` field in your OpenAPI spec is all it takes.
82+
83+
---
84+
85+
### Sunset Headers: Communicating the Timeline
86+
87+
Deprecation signals intent. The [Sunset HTTP header](https://datatracker.ietf.org/doc/html/rfc8594) (RFC 8594) signals a deadline. Barbacane supports both through a single extension:
88+
89+
```yaml
90+
paths:
91+
/v1/users/{id}:
92+
get:
93+
deprecated: true
94+
x-sunset: "Sat, 01 Jun 2026 00:00:00 GMT"
95+
summary: Get user by ID (use /v2/users/{id})
96+
x-barbacane-dispatch:
97+
name: http-upstream
98+
config:
99+
url: "https://api.example.com"
100+
```
101+
102+
The response now carries both signals:
103+
104+
```
105+
HTTP/1.1 200 OK
106+
Deprecation: true
107+
Sunset: Sat, 01 Jun 2026 00:00:00 GMT
108+
Content-Type: application/json
109+
```
110+
111+
The sunset date uses HTTP-date format (RFC 9110). It's machine-readable, so automated monitoring tools can alert consumers about approaching deadlines without manual outreach.
112+
113+
And because the `x-sunset` value lives in the spec, it's visible in code review, tracked in Git, and compiled into the artifact. The `/__barbacane/specs` endpoint preserves `x-sunset` in the served specs, so developer portals and API catalogs consuming those specs can display retirement timelines to consumers automatically.
114+
115+
---
116+
117+
### Telemetry: Knowing When It's Safe
118+
119+
The biggest blocker to API retirement is "we don't know who's still using it." The `barbacane_deprecated_route_requests_total` metric directly addresses this.
120+
121+
Because the metric is labeled by method, path, and API name, you can query Prometheus for exactly the data you need to make retirement decisions:
122+
123+
- **Is v1 traffic declining after the deprecation announcement?** Track the counter over time.
124+
- **Which endpoints are still receiving traffic?** Break down by path.
125+
- **Are specific consumers still calling deprecated routes?** Combine with authentication telemetry to identify API keys or JWT subjects hitting deprecated endpoints.
126+
127+
When the counter flatlines, the removal becomes a confident operation rather than a leap of faith. When it doesn't, the data tells you exactly which endpoints need targeted outreach before you can proceed.
128+
129+
---
130+
131+
### Removal: Just Remove From Spec
132+
133+
When the sunset date passes and traffic has migrated, retirement is a one-line change:
134+
135+
```yaml
136+
# Before: v1 and v2 coexist
137+
paths:
138+
/v1/users:
139+
get:
140+
deprecated: true
141+
x-sunset: "Sat, 01 Jun 2026 00:00:00 GMT"
142+
# ...
143+
/v2/users:
144+
get:
145+
# ...
146+
```
147+
148+
```yaml
149+
# After: v1 removed
150+
paths:
151+
/v2/users:
152+
get:
153+
# ...
154+
```
155+
156+
The compiler produces an artifact without v1 routes. Requests to `/v1/users` return `404`. No separate configuration to clean up. No documentation to reconcile. No routes that might linger because someone forgot to update a YAML file in a different repo.
157+
158+
For multi-spec architectures, it's equally clean. Remove the spec file from the compile command:
159+
160+
```bash
161+
# Before
162+
barbacane compile \
163+
-s specs/users-v1.yaml \
164+
-s specs/users-v2.yaml \
165+
-m barbacane.yaml \
166+
-o gateway.bca
167+
168+
# After
169+
barbacane compile \
170+
-s specs/users-v2.yaml \
171+
-m barbacane.yaml \
172+
-o gateway.bca
173+
```
174+
175+
The compiled artifact now contains exactly one spec. The `/__barbacane/specs` endpoint reflects exactly what's running. There is no residual state.
176+
177+
---
178+
179+
### Git as the Lifecycle Ledger
180+
181+
In Barbacane's workflow, the full lifecycle of an API version, from introduction to deprecation to retirement, is captured in Git history:
182+
183+
1. **Introduction:** A PR adds `specs/users-v1.yaml` and includes it in the compile command
184+
2. **Deprecation:** A PR adds `deprecated: true` and `x-sunset` to v1 operations
185+
3. **Retirement:** A PR removes v1 routes or the entire spec file
186+
187+
Each transition is a reviewable, approvable change. The commit history answers questions that traditional gateways struggle with:
188+
189+
- *When was v1 deprecated?* Check the PR that added `deprecated: true`.
190+
- *What was the announced sunset date?* Read the `x-sunset` value in that same diff.
191+
- *Who approved the retirement?* Check the PR that removed the spec.
192+
- *What exactly changed when v1 was retired?* The spec diff shows every route that disappeared.
193+
194+
For organizations with compliance requirements around change management, this audit trail covers the entire API lifecycle with no additional tooling.
195+
196+
---
197+
198+
### Migration Incentives
199+
200+
Clear deprecation signals and sunset dates reduce friction, but sometimes consumers need a stronger nudge. Rate limiting on deprecated versions encourages timely upgrades:
201+
202+
```yaml
203+
# specs/users-v1.yaml (deprecated, reduced quota)
204+
paths:
205+
/v1/users:
206+
get:
207+
deprecated: true
208+
x-sunset: "Sat, 01 Aug 2026 00:00:00 GMT"
209+
x-barbacane-middlewares:
210+
- name: rate-limit
211+
config:
212+
quota: 10 # was 100
213+
window: 60
214+
partition_key: "header:x-api-key"
215+
216+
# specs/users-v2.yaml (current, full quota)
217+
paths:
218+
/v2/users:
219+
get:
220+
x-barbacane-middlewares:
221+
- name: rate-limit
222+
config:
223+
quota: 100
224+
window: 60
225+
partition_key: "header:x-api-key"
226+
```
227+
228+
The deprecation policy is visible in the spec diff. A reviewer can see, in a single pull request, that v1's quota dropped from 100 to 10 while v2 remains unchanged. The intent is self-documenting.
229+
230+
---
231+
232+
### CI/CD as the Safety Net
233+
234+
Multi-spec compilation, which we covered in [One Gateway, Many Specs](/blog/one-gateway-many-specs/), gives you a compile-time safety net for retirement operations. Block merges to `main` if the combined specs don't compile cleanly:
235+
236+
```yaml
237+
# .github/workflows/api-lifecycle.yml
238+
jobs:
239+
validate:
240+
runs-on: ubuntu-latest
241+
steps:
242+
- uses: actions/checkout@v4
243+
- name: Compile gateway artifact
244+
run: |
245+
barbacane compile \
246+
-s specs/users-v2.yaml \
247+
-s specs/orders-v2.yaml \
248+
-m barbacane.yaml \
249+
-o gateway.bca
250+
```
251+
252+
When you remove a spec from compilation, the compiler produces a new artifact with a smaller route set. A spec accidentally dropped from the compile command produces an artifact with fewer routes than expected. The pipeline ensures that retirement is intentional, not accidental.
253+
254+
---
255+
256+
### Strengths and Limitations
257+
258+
Barbacane's spec-driven model addresses the core challenge in API retirement: bridging the gap between intent and enforcement. But it's worth being precise about what it does and doesn't solve.
259+
260+
**What this approach gives you:**
261+
- **Zero-config deprecation.** `deprecated: true` in the spec → `Deprecation` header in the response → counter in Prometheus. No middleware, no plugins.
262+
- **Standards-compliant sunset signaling.** RFC 8594 `Sunset` header via `x-sunset`, machine-readable by any HTTP-aware tooling.
263+
- **Atomic retirement.** Removing a spec removes all its routes, middleware, and configuration in one operation. No partial states.
264+
- **Auditable lifecycle.** Every transition is a Git commit with a reviewable diff.
265+
- **No configuration residue.** There's no separate config layer where retired routes could linger.
266+
267+
**What it doesn't solve:**
268+
- **Consumer discovery.** Telemetry tells you *how much* traffic a version receives and from which identities, but Barbacane doesn't maintain a registry of registered consumers. If you need formal consumer onboarding and offboarding, that's a separate concern.
269+
- **Client-side migration.** The gateway can signal deprecation and reduce quotas, but it can't rewrite client code. SDK updates, migration guides, and direct outreach remain necessary.
270+
- **Automatic version negotiation.** Barbacane routes what the spec declares. Transparent redirects from v1 to v2, request transformation between versions - these are application concerns, not gateway concerns.
271+
272+
---
273+
274+
### The Bigger Picture
275+
276+
The apidays community recently highlighted API retirement as one of the most underserved areas of API lifecycle management. The diagnosis is accurate: most organizations lack the tooling and visibility to retire APIs confidently, so they don't. Versions accumulate. Operational overhead grows. Security surface expands.
277+
278+
The conventional response is to add process on top of existing tooling: retirement policies, sunset committees, usage audits. These help, but they're fighting against an architecture that wasn't designed for lifecycle management.
279+
280+
Barbacane's approach is different: don't add a retirement process on top of the gateway - make retirement a natural consequence of how the gateway already works. Mark an operation as deprecated in your spec: the gateway emits headers and metrics. Set a sunset date: consumers are notified automatically. Remove the route: it's gone. Everything in between lives in the same spec, reviewed in the same PRs, compiled into the same artifacts.
281+
282+
API retirement shouldn't require a committee. It should require a pull request.
283+
284+
---
285+
286+
*Barbacane is open source (Apache 2.0) and available at [github.com/barbacane-dev/barbacane](https://github.com/barbacane-dev/barbacane). Check the [documentation](https://docs.barbacane.dev/) for the full CLI reference and getting started guide.*

0 commit comments

Comments
 (0)