Business Software
Refitter and a BFF: Reducing the Cost of API Integration
Refitter can remove repetitive client code, while a Backend for Frontend keeps generated contracts away from the user experience. The business value is faster change with fewer translation defects, provided the API contract and generation process are treated as products rather than shortcuts.

The saving comes from removing repeated decisions
Refitter generates C# Refit interfaces and contract classes from an OpenAPI description. A Backend for Frontend, usually shortened to BFF, presents endpoints designed around the needs of one user interface. Used together, they can shorten a familiar delivery loop: interpret an API document, write request and response models, add routes and parameters, wire an HTTP client, translate several responses for the screen, then repeat much of that work when the contract changes.
The commercial case is not that generated code is quicker to type. Typing was rarely the expensive part. The cost sits in repeated interpretation, review, debugging and coordination. A generator turns the mechanical part of the provider contract into a repeatable build input. The BFF gives the product team one controlled place to turn that transport contract into a task-specific response for the frontend.
This can release meaningful development capacity and prevent defects, but no responsible team should promise a universal percentage. Savings vary with API quality, integration volume, team familiarity and how often contracts change. Measure the old and new delivery paths, including review and rework, then value capacity that can actually be reassigned.
Refitter and the BFF solve different problems
Refitter works at the outbound boundary. From OpenAPI it can generate the Refit interface and data contracts used by .NET code to call an API. The BFF works at the product boundary. It combines, filters and translates backend capabilities into operations that make sense to a particular web or mobile experience.
| Concern | Refitter contributes | The BFF contributes |
|---|---|---|
| Transport contract | Routes, verbs, parameters and serialisable types generated from OpenAPI | Keeps those details behind a product-facing endpoint |
| User journey | No knowledge of what a screen or workflow needs | Aggregates and shapes data for that journey |
| Change detection | Regeneration creates a visible compile or source diff | Contains the impact on the frontend contract |
| Failure handling | Provides typed access to HTTP calls and responses | Translates dependency failures into stable product outcomes |
| Ownership | Automates code derived from the provider contract | Owns deliberate application behaviour |
Confusing those responsibilities destroys much of the benefit. Generated types should not become the frontend's public model. If they do, a provider's property rename can ripple into view components, validation and tests. Conversely, writing every API call by hand inside the BFF wastes the automation opportunity and recreates contract drift.
Where development time is actually recovered
The first saving is client scaffolding. Teams stop repeatedly hand-writing DTOs, attributes, query parameters and routine registration for every operation. That reduction compounds across services and versions, especially where the alternative is copied client code with slightly different naming and error behaviour.
The larger saving often arrives during change. With deterministic generation, an updated OpenAPI document produces a reviewable difference. Removed operations, changed nullability and renamed properties become build or test work close to the contract boundary. Without it, the same incompatibility may remain hidden until a tester exercises a less common path or production receives a response the handwritten model cannot read.
The BFF reduces coordination time when a screen needs data from several services. Instead of making the browser understand three authentication schemes, pagination models and failure formats, the BFF owns that composition. Frontend work can proceed against a small experience contract while backend integration details evolve behind it.
There is also a support saving. One adapter layer can attach correlation, record dependency duration and translate known error codes consistently. Five components no longer need five subtly different explanations of the same upstream failure. Faster diagnosis is development capacity too, even though it appears in an operational queue rather than a sprint estimate.

Fewer lines do not automatically mean fewer bugs
Refitter can eliminate transcription defects: the wrong route, a missing query parameter, an inaccurate enum or a response property copied with the wrong type. It also makes contract changes more visible. Those are valuable improvements because they move detection towards generation, compilation and automated tests.
It cannot correct a false OpenAPI document. If the provider declares a field as required but sometimes omits it, generated code can be faithfully wrong. Generation concentrates trust in the specification, so specification validation and representative response tests become more important, not less.
The BFF prevents another class of defect by stopping frontend code from coordinating distributed operations. A browser should not decide whether two backend writes form one business action, nor should it invent recovery after one succeeds and the other times out. The BFF can expose one product operation and own its ordering, idempotency and failure semantics.
Yet aggregation introduces its own failure surface. One screen request may fan out to four dependencies. Its reliability is then constrained by all critical calls, and its latency can be dominated by the slowest. The correct lesson is not that a BFF removes integration risk. It gives the team a server-side place to control, observe and test that risk.
The safest boundary is generated transport, handwritten intent
Treat Refitter output as generated infrastructure. Do not casually edit it, and do not scatter it through business services. Put a narrow adapter around each generated client. The adapter should translate transport responses into application outcomes, attach authentication through managed handlers, propagate cancellation and expose only operations the BFF needs.
Then design BFF endpoints around user actions and display needs rather than mirroring upstream controllers. A dashboard endpoint might obtain account status, outstanding tasks and recent activity concurrently, return only fields the screen uses and distinguish a tolerable missing panel from a failure that makes the page unsafe to show.
This separation limits regeneration churn. Generated names and models may change while the application-facing adapter remains stable. It also makes replacement possible. Refitter is a productive implementation choice, but it should not become an architectural dependency in every layer of the product.
Measure the business case before quoting a saving
Choose several representative integration changes from recent delivery history. Include a new endpoint, a contract alteration and a composite frontend journey. For each, establish the effort spent on client creation, mapping, review, tests, defect correction and release support. Ticket timestamps alone are weak evidence because waiting time is not engineering effort; use pull requests, time records and incident history where available.
After introducing Refitter and the BFF, measure the same categories. Do not count generated lines as lines of productive code, and do not treat every removed hour as cash. Capacity has business value when it avoids external spend, delays recruitment, increases feature throughput or lets scarce engineers work on higher-value problems.
| Measure | Useful evidence | Misleading shortcut |
|---|---|---|
| Integration lead time | Start-to-production time for comparable contract changes | Time taken to generate one file |
| Engineering effort | Implementation, review, testing and rework hours | Handwritten lines deleted |
| Contract defects | Failures traced to routes, models, serialisation or response handling | All bugs in the feature |
| Escaped defects | Integration faults first found after release | Compiler warnings alone |
| Support effort | Time to identify dependency and contract failures | Total application support time |
| Capacity realised | Features, avoided spend or service work enabled | Gross hours multiplied by salary |
A credible pilot reports a range. If three integrations save between half a day and two days but build maintenance adds time, show both. The important result is whether the approach repeatedly shortens the critical path and changes what the team can deliver, not whether one percentage looks impressive in a presentation.
Make generation deterministic and reviewable
Refitter is available as a .NET CLI tool, an MSBuild task and a source generator. Its project currently recommends the MSBuild approach for build-time generation. Whichever route a team chooses, pin the tool and relevant package versions. A developer laptop downloading “latest” can produce a different client from the build agent next week.
Decide whether generated output is committed. Committing it makes contract changes visible in ordinary review and lets builds continue without fetching a remote specification. Generating during the build reduces repository noise but makes tool availability and the specification source part of build reliability. For business-critical systems, a useful compromise is to store the approved OpenAPI input, generate deterministically in CI and fail when regenerated output or contract tests differ unexpectedly.
Never consume a mutable production URL without control and call the result reproducible. Capture or version the specification used for a release. Review generator upgrades separately from API changes, because a tool update can alter naming, nullability or serialisation across a large client surface even when the provider contract did not change.
A BFF has an operating cost
A BFF adds a deployable service, another network hop and another place that needs security patches, monitoring and on-call ownership. Microsoft’s architecture guidance also warns about service lifecycle cost, latency and duplication. If one simple frontend calls one stable API with nearly identical models, the extra layer may cost more than it saves.
The pattern earns its keep when the frontend has distinct needs, several dependencies, sensitive tokens that should remain server-side, or a release cadence that is repeatedly blocked by a general-purpose backend. It is less convincing when labelled “BFF” but operated as a universal gateway for every client. That recreates the shared bottleneck under a new name.
Keep business rules in the system that owns them. A BFF may orchestrate a user journey, but duplicating pricing, eligibility or permission rules there creates inconsistent outcomes across channels. Authorisation must also remain enforced by the resource service. The BFF can reduce the exposed surface and forward identity securely; its presence is not proof that downstream access is allowed.
Production controls decide whether the saving survives
- Version and validate the OpenAPI input before generation.
- Pin Refitter, Refit and generator settings so builds remain reproducible.
- Keep generated types behind adapters rather than returning them from BFF endpoints.
- Run contract tests with representative success and error responses.
- Translate stable error codes once and avoid logging tokens or sensitive bodies.
- Apply retries by operation semantics. A timed-out write may have succeeded.
- Propagate cancellation and maintain an end-to-end timeout budget across fan-out calls.
- Trace one frontend request through the BFF and each dependency.
- Use idempotency or explicit recovery for multi-step user operations.
- Assign ownership for generator upgrades, API drift and production incidents.
These controls consume effort, but they are not overhead that invalidates automation. They are the mechanism that converts quick code generation into dependable delivery. Omitting them saves time only until the first invisible contract break or ambiguous partial write.
When we would recommend the combination
Refitter plus a BFF is a strong option for a .NET product team consuming well-described REST APIs, especially when the user experience combines several services or changes more frequently than those services. Start with one integration whose historical effort and defects are known. Automate generation, keep the adapter boundary narrow and measure the whole change path through production.
Use Refitter without a BFF when typed generation is valuable but the client can safely consume a simple API contract directly. Use a BFF without Refitter when upstream services are not described by usable OpenAPI or when they use protocols that need another client approach. Use neither when the extra toolchain and service cannot repay their ownership cost.
The durable business benefit is not code that nobody had to type. It is a delivery system in which routine contract work is repeatable, product-specific decisions are concentrated in one owned boundary, and incompatible change is discovered before customers discover it.