Skip to content

Latest commit

 

History

History
185 lines (153 loc) · 9.92 KB

File metadata and controls

185 lines (153 loc) · 9.92 KB

Diff

The oasdiff diff command displays the diff between OpenAPI specs.
Output is fully detailed, typically in yaml or json but also available in text, markdown and html formats.
This commmand is typically used to generate a structured diff report which can be consumed by other tools but it can also be viewed by humans.

Note: summary, breaking, and changelog are built on the same diff engine. Most concepts and flags described here apply to those commands too. Exceptions are called out inline.

Default Comparison Behaviour

oasdiff applies a few opt-out defaults so its diff matches what most users expect from a real-world API comparison, not a literal byte-level spec comparison. Each can be disabled with --<flag>=false if your use case needs the stricter behaviour.

Flag Default What it does Detail
--match-inline-refs true Match validation-equivalent inline / $ref subschemas under anyOf / oneOf as the same branch. Codegen refactors that pull an inline enum into a named component report no change. Matching Inline and $ref Subschemas
--case-insensitive-headers true Compare header names case-insensitively. Content-Type and content-type are the same header per RFC 7230 / 9110. HEADER-DIFF.md
--allow-external-refs true Allow the parser to resolve external $refs when loading specs. Disable when processing untrusted specs to prevent SSRF. (CLI help)

All other comparison-tuning flags (--flatten-allof, --flatten-params, --include-path-params, --auto-upgrade, ...) are opt-in (default false) because they transform the input or change matching semantics in ways that not every spec wants.

Output Formats

The default diff output format is yaml.
Additional formats can be generated using the --format flag:

  • yaml: includes all diff details
  • json: includes all diff details
  • text: designed to be more user-friendly and provide only the most important parts of the diff (same as markdown)
  • markdown: designed to be more user-friendly and provide only the most important parts of the diff (same as text)
  • html: designed to be more user-friendly and provide only the most important parts of the diff (see also changelog with html)

Notes:

  • an empty yaml or json result signifies that the diff is empty, or, in other words, there are no changes.
  • the json format excludes the endpoints section to avoid the complex mapping keys problem.

Preventing Changes

A common way to use oasdiff diff is by running it as a step the CI/CD pipeline to detect changes.
In order to prevent changes, oasdiff diff can be configured to return an error if changes are found.
To exit with return code 1 if any changes are found, add the --fail-on-diff flag.

Paths vs. Endpoints

OpenAPI Specification has a hierarchical model of Paths and Operations (HTTP methods).
Oasdiff follows this hierarchy and displays a hierarchical diff with path changes: added, deleted and modified, and within the latter, "modified" section, another set of operation changes: added, deleted and modified. For example:

paths:
    deleted:
        - /register
        - /subscribe
    modified:
        /api/{domain}/{project}/badges/security-score:
            operations:
                modified:
                    GET:

Oasdiff also outputs an alternate simplified diff per "endpoint" which is a combination of Path + Operation, for example:

endpoints:
    deleted:
        - method: POST
          path: /subscribe
        - method: POST
          path: /register
    modified:
        ?   method: GET
            path: /api/{domain}/{project}/badges/security-score
        :   tags:
                deleted:
                    - security

Complex Mapping Keys

The modified endpoints section has two items per key, method and path, this is called a complex mapping key in YAML.
Some YAML libraries don't support complex mapping keys, for exampple:

To overcome this limitation, oasdiff allows you to exclude the endpoints section by adding the following flag: --exclude-elements=endpoints.
When using json output format, oasdiff excludes endpoints automatically.

OpenAPI Extensions

Oasdiff tracks changes to OpenAPI extensions by default. To disable this, see Excluding Specific Kinds of Changes.
The diff format for OpenAPI extensions conforms with JavaScript Object Notation (JSON) Patch, for example:

endpoints:
    modified:
        ?   method: POST
            path: /example/callback
        :   extensions:
                modified:
                    x-amazon-apigateway-integration:
                        - oldValue: "201"
                          value: "200"
                          op: replace
                          from: ""
                          path: /responses/default/statusCode
                        - oldValue: http://api.example.com/v1/example/callback
                          value: http://api.example.com/v1/example/calllllllllback
                          op: replace
                          from: ""
                          path: /uri

Excluding Specific Kinds of Changes

Currently available on diff and summary.

You can use the --exclude-elements flag with to exclude one or more of the following:

  • Use --exclude-elements examples to exclude Examples
  • Use --exclude-elements extensions to exclude Extensions
  • Use --exclude-elements description to exclude description fields
  • Use --exclude-elements title to exclude title fields
  • Use --exclude-elements summary to exclude summary fields
  • Use --exclude-elements endpoints to exclude the endpoints section of the diff

For example, this diff excludes descriptions and examples:

oasdiff diff data/openapi-test1.yaml data/openapi-test3.yaml --exclude-elements description,examples -f text

Excluding Specific Extension Names

If you want to exclude specific OpenAPI extensions by name while keeping others, use the --exclude-extensions flag. This is different from --exclude-elements extensions which excludes ALL extensions.

For example, to exclude only x-internal and x-ignore extensions while keeping all others:

oasdiff diff base.yaml revision.yaml --exclude-extensions x-internal,x-ignore

This is useful when you have extensions that are only used internally or for tooling purposes (e.g., x-codegen-ignore, x-internal) and you don't want changes to these extensions to appear in the diff.

Matching Inline and $ref Subschemas

Under anyOf and oneOf, oasdiff treats an inline subschema and a $ref to a validation-equivalent component as the same branch by default. This catches a common codegen pattern where a tool extracts an inline schema (often an enum) into a named component without changing the accepted payloads:

# base
role:
  anyOf:
    - type: string
      enum: [user, admin]
    - type: "null"

# revision (UserRole is { type: string, enum: [user, admin] })
role:
  anyOf:
    - $ref: "#/components/schemas/UserRole"
    - type: "null"

The diff reports no change for the anyOf list because the union of accepted payloads is identical. The same behaviour applies to breaking and changelog, which run on the same diff engine.

To restore the previous behaviour where the inline branch is reported as removed and the $ref branch as added, pass --match-inline-refs=false.

Annotation-only differences (title, description, default, example, examples, external docs, $comment) are ignored for the equivalence check. Differences that affect validation (including deprecated) are not. Component $ref renames (both sides $ref, e.g. UserRoleV1 to UserRole) and inline-to-inline edits are out of scope by design: only the inline-to-$ref form change is treated as no-change.

The matching is pair-based: each deleted branch matches at most one added branch. An added $ref that happens to be equivalent to an inline branch already present on the base (a standalone addition that overlaps an existing branch, rather than a refactor) is still reported as added.

Usage Examples

Diff as YAML

oasdiff diff data/openapi-test1.yaml data/openapi-test2.yaml

The default diff output format is yaml.
No output means that the diff is empty, or, in other words, there are no changes.

Text/Markdown Diff Report

oasdiff diff data/openapi-test1.yaml data/openapi-test2.yaml -f text

The text diff report provides a simplified and partial view of the changes. It is also compatible with markdown.
To view all diff details, use yaml or json formats.

HTML Diff Report

oasdiff diff data/openapi-test1.yaml data/openapi-test2.yaml -f html 

The html diff report provides a simplified and partial view of the changes.
To view all diff details, use yaml or json formats.

Comparing remote files over http/s

oasdiff diff https://raw.githubusercontent.com/oasdiff/oasdiff/main/data/openapi-test1.yaml https://raw.githubusercontent.com/oasdiff/oasdiff/main/data/openapi-test3.yaml -f text

Diff across multiple specs with globs

oasdiff diff "data/composed/base/*.yaml" "data/composed/revision/*.yaml" -c