Skip to content

Commit 8cacfca

Browse files
authored
Merge pull request #8 from barbacane-dev/blog/strangler-fig-pattern
Blog: Strangler Fig pattern with spec-driven API gateways
2 parents 865143d + 87d15d3 commit 8cacfca

File tree

1 file changed

+303
-0
lines changed

1 file changed

+303
-0
lines changed
Lines changed: 303 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,303 @@
1+
---
2+
title: "Gradual migration, zero downtime: the Strangler Fig pattern with spec-driven API gateways"
3+
description: "Instead of risky big-bang rewrites, the Strangler Fig pattern lets you modernize legacy systems incrementally. Learn how Barbacane's spec-driven, compiled approach makes it the ideal facade for safe, reversible migrations."
4+
publishDate: 2026-03-16
5+
author: "Nicolas Dreno"
6+
tags: ["barbacane", "api-gateway", "strangler-fig", "migration", "microservices", "openapi", "architecture"]
7+
draft: true
8+
---
9+
10+
*The Strangler Fig pattern, popularized by Martin Fowler, offers a pragmatic approach to modernizing legacy systems: instead of risky "big bang" rewrites, you incrementally replace functionality by routing traffic through a facade that gradually shifts requests from old to new systems.*
11+
12+
Modern API gateways are the ideal facade for this pattern. They provide the routing flexibility, policy enforcement, and observability needed to run legacy and new services side-by-side - safely and reversibly.
13+
14+
In this article, we'll explore how **Barbacane**, a spec-driven API gateway built in Rust, enables Strangler Fig migrations with compile-time safety, OpenAPI as configuration, and WASM-extensible middleware.
15+
16+
---
17+
18+
### What is the Strangler Fig pattern?
19+
20+
The Strangler Fig pattern helps modernize legacy systems incrementally, with reduced transformation risk and business disruption. Whether you're decomposing a monolith into microservices, migrating between platforms, replacing a third-party dependency, or upgrading a protocol layer, the approach is the same. The pattern works in three phases:
21+
22+
1. **Transform**: Introduce a facade (typically an API gateway) that intercepts all incoming requests
23+
2. **Elongate**: Gradually route specific endpoints or features to new implementations while legacy code handles the rest
24+
3. **Strangle**: Once all functionality is migrated, retire the legacy system entirely
25+
26+
The key insight: **you never have two systems "live" for the same endpoint**. The gateway ensures requests go to exactly one backend at a time, eliminating race conditions and data inconsistencies.
27+
28+
---
29+
30+
### Why modern API gateways excel at Strangler Fig migrations
31+
32+
Traditional gateways often require separate configuration languages, creating drift between your API contract and runtime behavior. New-generation gateways like Barbacane solve this by making **your OpenAPI spec the single source of truth**.
33+
34+
#### Key capabilities for incremental migration
35+
36+
| Capability | Why it matters for Strangler Fig |
37+
|------------|----------------------------------|
38+
| **Spec-driven routing** | Define routes in OpenAPI; no separate DSL to maintain or sync |
39+
| **Path-level dispatch** | Route `/v1/users` to legacy, `/v2/users` to new service - same spec, different backends |
40+
| **Middleware chaining** | Apply auth, rate limiting, or transformation logic uniformly across old and new endpoints |
41+
| **Compile-time validation** | Catch routing conflicts, missing backends, or security misconfigurations before deployment |
42+
| **WASM plugins** | Extend gateway behavior safely without recompiling the core runtime |
43+
44+
---
45+
46+
### Implementing Strangler Fig with Barbacane: a step-by-step example
47+
48+
Let's walk through migrating a legacy `/users` endpoint to a new microservice.
49+
50+
#### Phase 1: Establish the facade
51+
52+
Start by defining your API in OpenAPI and adding Barbacane's `x-barbacane-dispatch` extension to route all traffic to the legacy system:
53+
54+
```yaml
55+
# api.yaml
56+
openapi: "3.1.0"
57+
info:
58+
title: User API
59+
version: "1.0.0"
60+
61+
paths:
62+
/users:
63+
get:
64+
summary: List users
65+
responses:
66+
'200':
67+
description: Success
68+
x-barbacane-dispatch:
69+
name: http-upstream
70+
config:
71+
url: "https://legacy-monolith.internal"
72+
path: "/api/v1/users"
73+
```
74+
75+
Compile and deploy:
76+
77+
```bash
78+
barbacane compile --spec api.yaml --manifest plugins.yaml --output api.bca
79+
barbacane serve --artifact api.bca --listen 0.0.0.0:8080
80+
```
81+
82+
All traffic now flows through Barbacane, but still reaches the legacy backend.
83+
84+
#### Phase 2: Elongate - migrate one endpoint
85+
86+
Now extract the `GET /users` endpoint to a new service. Update the spec to route just this operation to the new backend:
87+
88+
```yaml
89+
paths:
90+
/users:
91+
get:
92+
summary: List users (new implementation)
93+
responses:
94+
'200':
95+
description: Success
96+
x-barbacane-dispatch:
97+
name: http-upstream
98+
config:
99+
url: "https://user-service.internal" # New microservice
100+
path: "/users"
101+
```
102+
103+
Other endpoints (e.g., `POST /users`, `/users/{id}`) remain routed to the legacy system. No code changes elsewhere, just update the spec and recompile.
104+
105+
**Traffic is now split**: reads go to the new service, writes still hit the monolith. You can validate behavior, monitor performance, and roll back instantly by reverting the spec.
106+
107+
#### Phase 3: Apply cross-cutting concerns uniformly
108+
109+
Use global middleware to apply policies across both legacy and new endpoints:
110+
111+
```yaml
112+
# Global middleware (applies to all operations)
113+
x-barbacane-middlewares:
114+
- name: rate-limit
115+
config:
116+
quota: 100
117+
window: 60
118+
- name: cors
119+
config:
120+
allowed_origins: ["https://app.example.com"]
121+
- name: correlation-id
122+
config:
123+
header_name: "X-Request-ID"
124+
generate_if_missing: true
125+
```
126+
127+
Operation-specific middleware can override or extend the chain:
128+
129+
```yaml
130+
paths:
131+
/users:
132+
get:
133+
x-barbacane-middlewares:
134+
- name: cache
135+
config:
136+
ttl: 300 # Cache GET /users for 5 minutes
137+
# ... dispatch config
138+
```
139+
140+
This ensures consistent security, observability, and performance policies regardless of which backend handles the request.
141+
142+
#### Phase 4: Deprecate and sunset legacy endpoints
143+
144+
As you migrate more functionality, mark legacy endpoints for retirement using OpenAPI's `deprecated` field and Barbacane's `x-sunset` extension:
145+
146+
```yaml
147+
paths:
148+
/v1/users:
149+
get:
150+
deprecated: true
151+
x-sunset: "Sat, 31 Dec 2026 23:59:59 GMT"
152+
summary: Legacy user endpoint (use /v2/users)
153+
x-barbacane-dispatch:
154+
name: http-upstream
155+
config:
156+
url: "https://legacy-monolith.internal"
157+
```
158+
159+
Clients receive `Deprecation: true` and `Sunset` headers, giving them time to migrate. When the sunset date arrives, simply remove the route from your spec.
160+
161+
#### Phase 5: Strangle - remove the legacy
162+
163+
Once all endpoints are migrated:
164+
165+
1. Remove legacy dispatch configurations from your OpenAPI spec
166+
2. Recompile the artifact
167+
3. Decommission the monolith
168+
169+
Migration complete - with zero downtime and full auditability via your version-controlled spec.
170+
171+
---
172+
173+
### Advanced patterns
174+
175+
#### Wildcard routing for bulk migration
176+
177+
Use greedy path parameters (`{path+}`) to proxy entire subtrees during early migration phases:
178+
179+
```yaml
180+
# Proxy all /legacy/* paths to the monolith
181+
/legacy/{path+}:
182+
get:
183+
parameters:
184+
- name: path
185+
in: path
186+
required: true
187+
allowReserved: true
188+
schema: { type: string }
189+
x-barbacane-dispatch:
190+
name: http-upstream
191+
config:
192+
url: "https://legacy-monolith.internal"
193+
path: "/{path}"
194+
```
195+
196+
As you extract services, replace wildcard routes with specific paths pointing to new backends.
197+
198+
#### Mock dispatchers for contract-first development
199+
200+
Before a new service is ready, use Barbacane's `mock` dispatcher to stub responses and validate client integrations:
201+
202+
```yaml
203+
/users/{id}:
204+
get:
205+
x-barbacane-dispatch:
206+
name: mock
207+
config:
208+
status: 200
209+
body: '{"id":"123","name":"Test User"}'
210+
```
211+
212+
Switch to `http-upstream` when the real service is deployed - no client changes needed.
213+
214+
#### AsyncAPI for event-driven migration
215+
216+
Barbacane supports AsyncAPI 3.x, enabling sync-to-async bridging. Publish events from HTTP endpoints to Kafka or NATS while legacy systems still poll databases:
217+
218+
```yaml
219+
# AsyncAPI operation exposed via HTTP POST
220+
/events/user.created:
221+
post:
222+
x-barbacane-dispatch:
223+
name: kafka
224+
config:
225+
topic: "user-events"
226+
brokers: "kafka:9092"
227+
```
228+
229+
This lets you decouple systems incrementally without rewriting consumers upfront.
230+
231+
---
232+
233+
### Why Barbacane's compilation model reduces migration risk
234+
235+
Unlike configuration-driven gateways, Barbacane **compiles your OpenAPI spec into a portable `.bca` artifact**. This provides critical safety guarantees:
236+
237+
- **Routing conflicts** (same path+method in multiple specs) are caught at compile time (error `E1010`)
238+
- **Missing dispatchers** trigger validation errors (`E1020`) before deployment
239+
- **Insecure upstream URLs** (`http://`) are rejected by default in production builds (`E1031`)
240+
- **Path template errors** (invalid wildcards, duplicate params) fail fast (`E1054`)
241+
242+
This means your Strangler Fig migration is **validated before it reaches production** - no more "works on my machine" surprises.
243+
244+
---
245+
246+
### Observability: monitor your migration in real time
247+
248+
Barbacane emits Prometheus metrics, structured logs, and OpenTelemetry traces out of the box. During migration, track:
249+
250+
```promql
251+
# Compare latency between legacy and new endpoints
252+
rate(barbacane_request_duration_seconds_sum{path="/v1/users"}[5m])
253+
/
254+
rate(barbacane_request_duration_seconds_count{path="/v1/users"}[5m])
255+
256+
# Monitor SLO violations on migrated endpoints (requires observability middleware)
257+
increase(barbacane_plugin_observability_slo_violation{path="/users"}[1h])
258+
```
259+
260+
Use the built-in Grafana dashboards (available in the [Playground](https://github.com/barbacane-dev/playground)) to visualize traffic shifting, error rates, and middleware performance.
261+
262+
---
263+
264+
### Getting started
265+
266+
1. **Try the Playground**:
267+
```bash
268+
git clone https://github.com/barbacane-dev/playground
269+
cd playground && docker-compose up -d
270+
# Gateway: http://localhost:8080 | Control Plane: http://localhost:3001
271+
```
272+
273+
2. **Read the Docs**: Full reference at [docs.barbacane.dev](https://docs.barbacane.dev)
274+
275+
3. **Start Small**: Pick one low-risk endpoint, define it in OpenAPI, and route it through Barbacane. Iterate from there.
276+
277+
---
278+
279+
### Conclusion
280+
281+
The Strangler Fig pattern works because it trades big-bang risk for **incremental change, continuous validation, and reversible decisions**. Modern API gateways like Barbacane amplify this approach by making your API spec the executable contract for routing, policy, and observability.
282+
283+
By compiling OpenAPI into portable artifacts, enforcing safety at build time, and supporting extensible middleware via WASM, Barbacane lets you strangle legacy systems with confidence - one endpoint at a time.
284+
285+
*Ready to start your migration? Explore the [Barbacane Playground](https://github.com/barbacane-dev/playground) or dive into the [documentation](https://docs.barbacane.dev).*
286+
287+
---
288+
289+
### Resources
290+
291+
- [Barbacane Documentation](https://docs.barbacane.dev)
292+
- [Interactive Playground](https://github.com/barbacane-dev/playground)
293+
- [GitHub Repository](https://github.com/barbacane-dev/barbacane)
294+
- [Strangler Fig Pattern (Martin Fowler)](https://martinfowler.com/bliki/StranglerFigApplication.html)
295+
- [AWS Prescriptive Guidance: Strangler Fig](https://docs.aws.amazon.com/prescriptive-guidance/latest/cloud-design-patterns/strangler-fig.html)
296+
297+
---
298+
299+
> **Pro Tip**: Keep your OpenAPI spec in version control alongside your application code. Every migration step becomes a reviewable, reversible commit - turning infrastructure changes into collaborative, auditable workflows.
300+
301+
---
302+
303+
*Barbacane is open source and available at [github.com/barbacane-dev/barbacane](https://github.com/barbacane-dev/barbacane). Questions or feedback? Reach us at [contact@barbacane.dev](mailto:contact@barbacane.dev).*

0 commit comments

Comments
 (0)