OpenAPI Specification Diff Tool

Tufin
3 min readFeb 24, 2021

--

By Reuven Harrison

tl;dr oasdiff is a tool for comparing OpenAPI Specifications; also a Go module.

OpenAPI Specification (previously known as Swagger) is a standard for documenting REST APIs. Here’s a small example:

info:
title: Tufin
version: 1.0.0
openapi: 3.0.3
paths:
/api/audit:
get:
parameters:
- in: query
name: limit
required: true
schema:
description: Non-negative integers
example: '1000'
format: non-negative integer
pattern: '^(?:\d+)$'
type: integer
responses:
'200':
description: OK

While working with OpenAPI, we needed to track API changes. We found some diff tools but they ignored certain kinds of changes, for example, there was no indication of schema changes. So we decided to create oasdiff, a Go module for comparing OpenAPI Specifications.

You can use oasdiff to compare two versions of an OpenAPI spec using the oasdiff docker image, like this:

docker run --rm -t tufin/oasdiff -base https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test1.yaml -revision https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test3.yaml

oasdiff provides a comprehensive and deep comparison of the API specs, all the way down to their parameters, bodies and schemas, recursively. For example:

spec:
paths:
deleted:
- /subscribe
- /api/{domain}/{project}/install-command
- /register
modified:
/api/{domain}/{project}/badges/security-score:
operations:
added:
- POST
modified:
GET:
tags:
deleted:
- security
parameters:
deleted:
cookie:
- test
header:
- user
- X-Auth-Name
modified:
path:
domain:
schema:
type:
from: string
to: integer
format:
from: hyphen-separated list
to: non-negative integer
description:
from: Hyphen-separated list of lowercase string
to: Non-negative integers (including zero)
min:
from: null
to: 7
pattern:
from: ^(?:([a-z]+-)*([a-z]+)?)$
to: ^(?:\d+)$
query:
filter:
content:
schema:
properties:
modified:
color:
type:
from: string
to: number
image:
explode:
from: null
to: true
schema:
description:
from: alphanumeric
to: alphanumeric with underscore, dash, period, slash and colon
token:
schema:
anyOf: true
type:
from: string
to: ""
format:
from: uuid
to: ""
description:
from: RFC 4122 UUID
to: ""
pattern:
from: ^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12})$
to: ""
responses:
added:
- default
deleted:
- "200"
- "201"
parameters:
deleted:
path:
- domain
security:
deleted:
- bearerAuth
servers:
deleted:
- tufin.com
tags:
deleted:
- security
- reuven
components:
schemas:
deleted:
- rules
- network-policies
parameters:
deleted:
header:
- network-policies
headers:
deleted:
- testc
- new
- test
requestBodies:
deleted:
- reuven
responses:
deleted:
- OK
securitySchemes:
deleted:
- OAuth
- bearerAuth

To get a simplified text/markdown report add the format flag:

docker run --rm -t tufin/oasdiff -format text -base https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test1.yaml -revision https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test3.yaml

Or as HTML:

docker run --rm -t tufin/oasdiff -format html -base https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test1.yaml -revision https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test3.yaml

The text/markdown report looks like this:

### New Endpoints
-----------------
### Deleted Endpoints
---------------------
POST /register
POST /subscribe
### Modified Endpoints
----------------------
GET /api/{domain}/{project}/badges/security-score
* Modified cookie param: test
- Content changed
* Modified query param: filter
- Content changed
- Schema changed
* Modified query param: image
* Modified header param: user
- Schema changed
- Schema added
- Content changed
* Response changed
- New response: default
- Deleted response: 200
- Modified response: 201
- Content changed
- Schema changed
- Type changed from 'string' to 'object'
GET /api/{domain}/{project}/install-command
* Deleted header param: network-policies
* Response changed
- Modified response: default
- Description changed from 'Tufin1' to 'Tufin'
- Headers changed
- Deleted header: X-RateLimit-Limit

You can also embed oasdiff into your Go program like this:

d := diff.Get(&diff.Config{}, base, revision)

For a full example, see https://github.com/Tufin/oasdiff/blob/main/main.go

I hope you find it useful.

Reuven

--

--

Tufin

From the Security Policy Company. This blog is dedicated to cloud-native topics such as Kubernetes, cloud security and micro-services.