|
| 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