Minimal API Migration
<!--
Work info
-->
Company:
VAE, Inc.
Role:
Software Engineer
Year:
2026

Project Overview
This project focuses on incrementally converting a legacy ASP.NET codebase from traditional controller-based APIs to ASP.NET Minimal APIs. The goal is to modernize the API surface while improving clarity, reducing boilerplate, and aligning the codebase with more explicit, composable patterns.
This work is still in progress. Rather than a wholesale rewrite, the conversion is being approached deliberately and incrementally, balancing modernization with stability in a production system.
Background & Motivation
While working in the existing codebase, I began to notice recurring friction points in the controller-based approach:
Controllers had grown large and difficult to reason about
Routing, authorization, binding, and business logic were often intertwined
Simple endpoints required significant ceremony
Cross-cutting concerns were handled inconsistently across controllers
Although controllers are a familiar and powerful abstraction, many endpoints no longer benefited from the structure they imposed. In several cases, the abstraction obscured intent rather than clarifying it.
Minimal APIs offered an opportunity to:
make endpoint behavior explicit at the point of definition
reduce indirection between routing and execution
compose concerns more intentionally
modernize without introducing a new framework
Problem Statement
The core problem was not that controllers were “wrong,” but that their cost had begun to outweigh their benefit for many endpoints.
Specifically:
Endpoint behavior was spread across attributes, base classes, and filters
Understanding an endpoint often required jumping between files
Boilerplate obscured the actual logic being executed
Adding new endpoints required copying patterns without always understanding them
As the system evolved, this made the API layer harder to change confidently.
Approach & Constraints
Several constraints shaped how this conversion could begin:
The codebase is production-critical and cannot be rewritten wholesale
Existing routing and authorization behavior must be preserved
Minimal APIs must integrate cleanly with existing middleware
Dependency injection and logging must remain explicit and predictable
The conversion must coexist with controller-based endpoints during transition
Given these constraints, the approach was to introduce Minimal APIs selectively, using them where they provided immediate clarity without destabilizing the system.
Early Decisions
Favor incremental adoption over full migration
Rather than attempting a large-scale rewrite, I started by identifying endpoints that:
were simple and self-contained
had minimal shared state
suffered most from controller overhead
These endpoints were good candidates for early conversion and learning.
Make behavior explicit at the endpoint boundary
Minimal APIs place routing, binding, authorization, and execution logic in one place. I leaned into this by:
defining dependencies explicitly in method signatures
making authorization requirements visible at the endpoint level
keeping endpoint logic small and focused
This helped make each endpoint understandable in isolation.
Preserve existing behavior before improving structure
Early conversions prioritized behavioral parity over refactoring. The goal was to:
match existing request/response shapes
preserve status codes and error handling
avoid introducing breaking changes
Structural improvements can follow once confidence is established.
Early Implementation Work
Initial work involved:
defining Minimal API endpoints alongside existing controllers
wiring routing and authorization to match legacy behavior
validating request binding and cancellation token behavior
ensuring logging and dependency injection behaved consistently
This phase surfaced subtle differences in how Minimal APIs handle:
model binding
cancellation token propagation
filter and middleware interaction
Each difference required careful validation rather than assumption.
Open Questions & Active Exploration
Because this work is ongoing, several questions are still being evaluated:
When does controller structure still provide meaningful value?
How should shared logic be factored without recreating controller-like abstractions?
What patterns scale cleanly as the number of Minimal APIs grows?
How should testing strategy evolve for endpoint-centric definitions?
These questions are shaping how the conversion proceeds and where Minimal APIs are appropriate.
Tradeoffs & Risks
Early tradeoffs include:
Reduced familiarity for engineers used to controllers
Risk of inconsistent patterns during transition
Additional upfront thought required to structure endpoints well
These risks are being managed by:
limiting initial scope
documenting emerging patterns
favoring clarity over cleverness
Current Status
At this stage:
Minimal APIs have been introduced selectively
Early endpoints are live and behaving as expected
Patterns are beginning to emerge, but are not yet locked in
Further refactoring and standardization are planned
This case study will evolve as the work matures.
Reflections (So Far)
Even early in the process, a few insights are already clear:
Minimal APIs reward intentional design
Reduced abstraction increases both power and responsibility
Explicitness improves confidence when changing code
Modernization works best when it’s incremental
What I’m Intentionally Not Doing (Yet)
I am intentionally not:
forcing all endpoints into Minimal APIs
abstracting prematurely to “standardize” patterns
removing controllers that still serve a clear purpose
Restraint at this stage is critical to avoid trading one form of complexity for another.
Results
Improvement in feature engagement
Customer support interactions
App Store rating




