Upstream OpenAPI Release Impact Report for Pinned Clients avatar

Upstream OpenAPI Release Impact Report for Pinned Clients

Pricing

from $30.00 / 1,000 run starteds

Go to Apify Store
Upstream OpenAPI Release Impact Report for Pinned Clients

Upstream OpenAPI Release Impact Report for Pinned Clients

Compare a pinned OpenAPI or Swagger document with the current upstream document. The Actor reports every changed operation and every changed schema with a JSON pointer, the old value, the new value, a change class, and a breaking flag, and it answers one

Pricing

from $30.00 / 1,000 run starteds

Rating

0.0

(0)

Developer

kingii98

kingii98

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

12 days ago

Last modified

Categories

Share

Compare the pinned OpenAPI or Swagger document that your client was generated from with the current upstream document, and get one answer: is it safe to bump?

The Actor reads two public documents with one GET each, builds a structural index of every operation and every schema, and reports each difference with a JSON pointer, the old value, the new value, a change class, and a breaking flag. No browser, no authentication, no proxy, no LLM.

Who this is for

The maintainer of a generated or hand-written client SDK that wraps a fast-moving upstream API. Before an upgrade, this person must know which upstream schema changes break the pinned decoder.

A worked example: a field chunkTimeout changes from integer to integer | false upstream. The generated decoder still reads int?, so the first server that answers false throws at decode time. The Actor calls that change type-widened and marks it breaking, with the exact pointer.

What the Actor does

  1. Fetches the baseline document and the current document. Each hop of each redirect is checked again against the private-address rules.
  2. Parses JSON or YAML. YAML aliases are refused, so an alias bomb cannot expand.
  3. Indexes both documents: every operation (GET /pets) and every schema (#/components/schemas/Pet, or #/definitions/Pet for Swagger 2).
  4. Compares the two indexes and classes every difference.
  5. Writes one summary record and one record for each changed operation and each changed schema.

Input

Every field has a default, so a run with an empty input {} works and compares the two public example documents.

FieldTypeDefaultMeaning
baselineSpecUrlURL stringpinned petstore exampleThe pinned OpenAPI or Swagger document, for example a raw file at a fixed commit.
currentSpecUrlURL stringpinned expanded petstore exampleThe current upstream document.
scopearray of strings[]Operation IDs, exact paths, or path prefixes that your client uses.
breakingRulesarray of change classesthe nine classes marked Yes belowWhich change classes count as breaking.
maxDepthinteger 1–128Maximum depth of the schema walk.
maxChangesPerEntityinteger 1–20050Maximum number of changes listed in one record.
timeoutSecsinteger 2–12030Per-document timeout.
maxRedirectsinteger 0–205Redirect hops followed for each document.
maxResponseBytesinteger 1000–2000000020000000Per-document body cap.

Scope

scope is the list of things your client actually calls. An entry matches an operation when it is equal to the operationId, equal to the path, or a prefix of the path. A schema is in scope when an operation in scope refers to it, directly or through another schema.

With a scope, every record carries usedByClient, and safeToBump looks only at the records in scope. A breaking change in an endpoint that your client never calls then keeps the bump safe.

Leave scope empty to keep every operation in scope; usedByClient is then null.

Change classes

ClassMeaningBreaking by default
operation-removedAn operation of the baseline is gone.Yes
operation-addedAn operation that the baseline does not have.No
operation-id-changedThe operationId changed. A generated method is renamed.No
response-code-removedA documented response code is gone.Yes
response-code-addedA new documented response code.No
field-removedA schema, a property, or a parameter is gone.Yes
field-addedA new schema, property, or parameter.No
required-addedA property, parameter, or request body became required.Yes
required-removedA property, parameter, or request body became optional.No
type-widenedThe type set grew, for example integer to integer or boolean.Yes
type-narrowedThe type set shrank.Yes
type-changedThe type set was replaced, for example integer to string.Yes
enum-value-removedAn enum value is gone.Yes
enum-value-addedA new enum value.No
ref-changedA $ref points at another schema.Yes

A widened type breaks a decoder, and a narrowed type breaks an encoder. Both are breaking by default, because a pinned client is usually both. Use breakingRules to change the set.

An absent type means "any type", which is the widest type of all: integer to absent is a widening, and absent to integer is a narrowing.

Only the top of an added or removed subtree is listed. The children of a new object are not repeated as separate changes.

Output

The dataset holds one summary record and one operation or schema record for each changed entity.

Entity record: recordType (operation or schema), entityId (GET /pets or Pet), pointer, status (changed, added or removed), operationId, path, method, schemaName, usedByClient, changeCount, breakingCount, breaking, changesTruncated, changes, comparedAt.

Each item of changes holds pointer, changeClass, from, to and breaking. A from or to of null means that the value did not exist on that side.

Summary record: ok, reasonCode, failedDocument, baselineSpecUrl, currentSpecUrl, baselineTitle, baselineVersion, currentTitle, currentVersion, specFormat, operationsCompared, schemasCompared, operationsChanged, schemasChanged, changeCount, breakingCount, entitiesBreaking, entitiesBreakingInScope, changeCounts, walkTruncated, scopeApplied, scopeSize, safeToBump, error, comparedAt.

safeToBump is true only when both documents were read and no breaking change touches an entity in scope.

Pointers

Pointers follow RFC 6901, with two stable extensions that survive reordering: a parameter is /paths/~1pets/get/parameters/{in}/{name}, and a response is /paths/~1pets/get/responses/{code}. The upstream document may list them in any order; the pointer stays the same.

Reason codes

OK, HTTP_ERROR, NOT_A_SPEC, DOCUMENT_TOO_LARGE, TIMEOUT, DNS_FAIL, CONNECT_FAIL, BLOCKED_TARGET, REDIRECT_LOOP, BAD_INPUT.

BAD_INPUT means that the Actor refused the input before any request: a URL with a scheme that is not HTTP(S), a URL with credentials, a URL with no hostname, a localhost target, two equal URLs, or a field outside its bounds. The summary record then holds the two URL fields as they were given, and failedDocument is null.

A document that cannot be read, a document that is not a spec, and an input that the Actor refuses are results, not faults. The run writes a summary record with ok: false, sets a status message, and succeeds. A failed run means a malfunction of the Actor itself.

Pricing

Pay per event. Three events:

EventUnitCounted
run-startedOne Actor runOnce, at the start of every run.
spec-pair-diffedOne baseline document compared with one current documentOnce, and only when both documents were read, parsed and compared. A run that could not read a document is not charged for it.
breaking-change-flaggedOne operation or schema marked breakingOnce for each entity record whose breaking is true. A record with ten breaking changes inside one schema is one event.

The count of breaking-change-flagged never exceeds what the run's maximum total charge allows.

Limits and safety

  • Two HTTP GET requests. No browser, no proxy, no authentication, no paid API, no LLM.
  • Only http and https. URLs with credentials, localhost targets, and hosts that resolve to a private or reserved address are refused, on the first request and on every redirect hop.
  • The body of each document is capped, the schema walk is depth-capped and cycle-safe, and the change list of each record is capped.

Local run

uv sync
uv run pytest
uv run ruff check .
apify run --input-file .actor/default_input.json