SOFTWARE / SYSTEMS / AIEngineering news. Technical depth.
Comparisons / 3 MIN READ

Generate API clients without hiding contract drift

Use generated transport code behind a thin handwritten adapter so schema changes stay visible to application reviewers.

Use generated clients for repetitive transport mechanics and a thin handwritten adapter for application semantics. Generation is valuable when the OpenAPI document is authoritative and reviewed; it becomes dangerous when a large generated diff silently changes naming, optionality, retries, or errors that the product relies on. Treat the generator, specification, configuration, and output as one versioned toolchain.

Compare the real responsibilities

A generated client can create request and response types, serialize parameters, construct URLs, and expose operations consistently. OpenAPI Generator’s repository documents generation of clients, server stubs, and documentation from OpenAPI descriptions across many languages and generators. That removes repetitive code, especially for broad APIs.

A handwritten fetch wrapper can express product-specific behavior directly: a stable InviteMember operation, a domain error union, cancellation, and one retry policy. It is easy to read when the API is small, but manual types and serializers can drift from the service contract. Teams often discover that their “simple wrapper” has become a partial, undocumented generator.

The combination is usually stronger. Keep generated code in an infrastructure package. Write a narrow adapter that accepts application concepts, calls the generated operation, performs runtime checks where trust changes, and maps transport errors into domain errors. UI code imports the adapter, not generator-specific models.

Make the specification the review surface

The OpenAPI Specification describes operations, parameters, request bodies, responses, and schemas. Require contract changes before implementation changes. Review examples and semantics, not only whether the file parses. A field changing from required to optional can be source-compatible in generated code while creating a new application state.

Pin the generator version, templates or template hash, configuration, and formatting tool. Regenerate in a clean environment. A reproducibility check should fail when committed output differs. Do not mix handwritten edits into generated files; they disappear on the next run and make diffs impossible to trust. Extend behavior through configuration, supported customization, or the adapter.

Keep generated diffs reviewable. Separate the contract change from unrelated generator upgrades. Summarize changed endpoints and models in the pull request, then inspect surprising churn. If a patch changes hundreds of files because a tool version altered formatting, land that mechanical update independently of a business change.

Keep runtime uncertainty visible

Static generated types describe what the specification promises, not necessarily what arrived over the network. At a boundary involving an independently deployed service or untrusted payload, validate critical discriminators, identifiers, and version fields at runtime. Decide what happens to unknown enum values; throwing deep inside rendering is weaker than mapping to an explicit unsupported case.

Centralize retry behavior. A generated client should not quietly retry non-idempotent requests because the UI adapter also retries. Pass deadlines and cancellation from the caller, define retryable status classes, and use idempotency keys where the service contract supports them. Map HTTP status, structured error code, and correlation ID before application code sees the failure.

Choose by change shape

Prefer generation when the API has many operations, multiple consumers, a mature specification, and a team willing to govern the toolchain. Prefer handwritten wrappers for a tiny, unstable internal API where the meaningful abstraction is much smaller than the wire surface. Use the hybrid when product semantics matter: generated transport plus stable handwritten ports.

Apply a six-item review: authoritative spec, pinned generator, reproducible output, isolated generated directory, explicit runtime trust checks, and one retry owner. Take the highest-change endpoint and put an adapter around it this sprint. The adapter’s return type should describe what the application can actually handle, even if the generated schema exposes twenty more fields.

Require an owner to explain every removed operation and newly optional field before accepting a generated diff.

SOURCES & REVIEW

Sources are linked throughout this guide. Product capabilities can change; consult the linked documentation for your deployment.

Read our editorial approach ↗