How AI is applied across API Evangelist and APIs.io. Read my AI disclosure →
API Evangelist API Evangelist
Discovery
Learnings
Guidance
Toolbox
Alignment
API Evangelist LLC

OpenAPI Overlays for Brownfield Correction Without Upstream Access

August 20th, 2026 · Kin Lane
OpenAPI Overlays for Brownfield Correction Without Upstream Access

Every integration I have ever built eventually runs into the same wall: the OpenAPI I am consuming is wrong, and I cannot fix it at the source. The price is documented as a string when the server sends a number. A field the API absolutely requires is missing from the required list. The server returns a 429 all day long, but the spec pretends that response does not exist. The servers block points at some placeholder URL a code generator dropped in. And when I go to file the fix upstream, I hit the usual brownfield reality — the vendor is slow, the spec is generated from annotations I do not control, or my one-line correction will get flattened the next time their pipeline regenerates the file. This is a different problem than the one I wrote about in separation of concerns, where I was intentionally layering my own local customizations on top of a fine spec. This is about a spec that is simply, factually buggy, and I do not own it.

The instinct is to fork the spec, hand-edit it, and move on. Do not do that. A fork silently drifts. Six months later nobody remembers which of the forty differences from upstream were deliberate bug fixes and which were accidental staleness. An OpenAPI Overlay is the honest alternative: a small, re-appliable patch that names exactly what is wrong and corrects it, and — critically — survives the next upstream regeneration because it targets the current document rather than replacing it. This is one of the use cases I flagged in The Many Use Cases for OpenAPI Overlays, and it is the one I reach for most in real consumer work.

Here is the first overlay against the Products API teaching template, pretending it is the buggy upstream. It fixes a wrong type, adds a missing required field, and documents the 429 the server actually returns.

overlay: 1.1.0
info:
  title: Products API correctness fixes
  version: 1.0.0
extends: https://raw.githubusercontent.com/api-evangelist/products-api/main/openapi/products-api-openapi.yml
actions:
  - target: $.components.schemas.Product.properties.price
    update:
      type: number
      format: float
      description: Unit price. Upstream documents this as a string; the API sends a JSON number.
  - target: $.components.schemas.Product
    update:
      required:
        - id
        - name
        - price
  - target: $.paths['/products'].get.responses
    update:
      '429':
        $ref: '#/components/responses/TooManyRequests'

Every action is a factual correction, and each one reads like a bug report. The price was typed as a string; I set it to a number and left a note in the description so the next person understands why. The required array upstream omitted price even though creates fail without it, so I state the real contract. And I wire in the 429/TooManyRequests response the server has always returned but the docs ignored — the TooManyRequests response with its application/problem+json example and RateLimit headers already exists in the components, upstream just never referenced it from the operation.

The second overlay handles the two failures that break tooling outright: a bad server URL and a wrong enum value.

overlay: 1.1.0
info:
  title: Products API server and enum fixes
  version: 1.0.0
extends: https://raw.githubusercontent.com/api-evangelist/products-api/main/openapi/products-api-openapi.yml
actions:
  - target: $.servers[0]
    update:
      url: https://api.products.example.com/v1
      description: Production. Replaces the placeholder localhost URL from code generation.
  - target: $.components.schemas.Product.properties.status
    update:
      enum:
        - active
        - inactive
        - cancelled

The servers[0] action swaps out the http://localhost placeholder a generator left behind — the single most common reason a downloaded spec is dead on arrival in Postman or an SDK generator. The status enum fix corrects a value that upstream spelled canceled while the cancel operation and the actual data use cancelled, so client validation stops rejecting valid records.

The whole point is repeatability. When the vendor regenerates their spec next week, I re-run these two overlays and my corrections snap right back into place, because they target $.components.schemas.Product.properties.price and $.servers[0], not some frozen copy. And the day upstream finally fixes the string-to-number bug on their end, I delete that one action and my patch shrinks. The overlay is self-documenting about what is still broken. That is the take I want to leave you with: stop forking specs you do not own, and stop waiting on a vendor’s backlog. An overlay is a bug report you can actually ship today.