Problem & Motivation
The way most organizations build APIs today is powerful but expensive. Even with good tools and modern frameworks, shipping and maintaining APIs still takes a lot more time, code, and coordination than it should. Before introducing a new approach, it’s important to make the pain points clear.
The current API development reality
Most teams follow one of two broad approaches to API development:
- Code-first – implement the API, then generate (Swagger-ui) or hand-write the contract after implementation is complete.
- Contract-first – design the contract (often using OpenAPI), then generate server/client stubs and fill in the logic.
Both approaches will work well technically, but in practice they share a core characteristic:
They still produce large amounts of bespoke service code for each and every API.
Each new service tends to re-implement the same patterns:
- Endpoint wiring and routing
- Request/response validation
- Authentication and authorization
- Error handling
- Logging, metrics, and tracing
- Database access, pagination, and filtering
Over time, this leads to a sprawling landscape of services that are similar but not quite the same, with subtle behavior differences hidden inside the code.
Contract-first vs. code-first – same outcome: lots of code
Contract-first improves design and alignment, but it doesn’t fundamentally change the deployment model:
- Design the contract
- Generate stubs - coupling contract to implementation
- Implement business and technical logic in code
- Deploy and operate yet another service
Code-first flips the order—write code first, then produce the contract—but the end result is similar: another bespoke service with its own implementation of cross-cutting concerns.
In both cases, the contract is mostly descriptive – it explains what the API is supposed to do, but it doesn’t run the API. The heavy lifting still happens in handwritten code.
Duplication of cross-cutting concerns
Because each service owns its own codebase, cross-cutting behaviors are often duplicated across many repositories:
- Security – auth, claims mapping, role checks, tenant scoping
- Observability – logging, metrics, tracing, correlation IDs
- Error handling – consistent problem responses, error codes, and retries
- Data access – pagination, filtering, sorting, soft deletes
Even with shared libraries and frameworks, this duplication has consequences:
- Small variations creep in from project to project
- Upgrades and fixes must be rolled out to many services
- New teams copy existing patterns, including old mistakes
The result is a platform where consistency is aspirational, but far from possible.
The cost of code-heavy APIs
This duplication shows up as concrete cost in several dimensions.
Long cycle time: idea → design → code → deploy
Even for a simple CRUD API, the journey often looks like:
- Draft requirements and initial data model
- Design the API (in a contract or in code)
- Create a new service or extend an existing one
- Implement endpoints, validation, and cross-cutting concerns
- Write tests, wire up CI/CD, deploy to environments
Each step involves multiple roles — product, architecture, developers, operations — and multiple feedback loops. The more services you have, the more of this you repeat.
Maintenance & onboarding complexity
Once APIs are in production, teams must:
- Keep many services patched, secure, and up to date
- Onboard new developers to many different codebases and patterns
- Coordinate changes across contracts, implementations, and consumers
Refactoring becomes expensive. A simple change in how you handle, say, pagination or error responses might require changes in dozens of services. Over time, teams accumulate accidental complexity that slows everything down.