This is a Translating parser for Prance, a library processing and validating OpenAPI specification files. It targets use cases when a specification spans across multiple files that need to be compiled to a single document, but inlining of the references objects is not desired or event possible.
Frameworks like Connexion unfortunately do not support file references in the specification and Prance can be used to alleviate this missing feature. Inlining can result in excessive memory usage and also can make code generators not work properly if they rely on properly reused component schema definitions. If the specification contains a recursive object definition, inlining would result in an infinite loop.
The original motivation is to make Red Hat Insights Host Inventory work with recursive objects defined in a schema that is incorporated to the OpenAPI specification of the application.
Imagine having an OpenAPI specification file that references an object from an external file. The current Resolving Parser would inline all of those, even if they were pointing to the same object, using a lot of memory. If the target object would recursively reference itself, such inlining wouldn’t be even possible.
openapi.spec.yaml
---
openapi: 3.0.3
info:
title: Example specification for the translating parser
version: 0.0.0
paths:
/hosts:
get:
responses:
default:
description: >-
An operation with a referenced schema.
content:
application/json:
schema:
$ref: 'schemas.yaml#/$defs/Response'
schemas.spec.yaml
---
$defs:
Response:
type: object
properties:
simple:
$ref: "#/$defs/Simple"
nested:
$ref: "#/$defs/Nested"
Simple:
type: object
Nested:
type: object
additionalProperties:
$ref: "#/$defs/Nested"
---
openapi: 3.0.3
info:
title: Example specification for the translating parser
version: 0.0.0
paths:
/hosts:
get:
responses:
default:
description: >-
An operation with a referenced schema.
content:
application/json:
schema:
type: object
properties:
simple:
type: object
nested:
type: object
additionalProperties:
<RECURSION!>
All references are removed and replaces with the referenced content. If a single object is referenced multiple times, the whole schema is inlined in place of each reference. In case of the recursive reference, this causes an infinite loop unless a custom Recursion Handler is provided.
---
openapi: 3.0.3
info:
title: Example specification for the translating parser
version: 0.0.0
paths:
/hosts:
get:
responses:
default:
description: >-
An operation with a referenced schema.
content:
application/json:
schema:
$ref: "#/components/schemas/schemas.spec.yaml_Response"
components:
schemas:
schemas.spec.yaml_Response:
type: object
properties:
simple:
$ref: "#/components/schemas/schemas.spec.yaml_Simple"
nested:
$ref: "#/components/schemas/schemas.spec.yaml_Nested"
schemas.spec.yaml_Simple:
type: object
schemas.spec.yaml_Nested:
type: object
additionalProperties:
$ref: "#/components/schemas/schemas.spec.yaml_Nested"
Here, the schemas from the external files are carried over to the original specification document. References remain references, just pointing to the Schemas collection. This applies to the recursive object too that is still recursive, only referencing itself in its new location.
- Get Pipenv.
$ pip install pipenv
- Install requirements.
$ pipenv sync
- ???
- Profit.
The core here is the TranslatingParser that can be used instead of Prance’s ResolvingParser to process the specification.
from translating_parser.parser import TranslatingParser
parser = TranslatingParser("openapi.spec.yaml")
parser.parse()
print(parser.specification)
There is a companion CLI script main.py that can be used to test and debug the parser.
usage: main.py [-h] [--parser PARSER] [--output-format OUTPUT_FORMAT]
[--verbose]
[file]
positional arguments:
file OpenAPI specification file. Default:
specs/openapi.spec.yaml
optional arguments:
-h, --help show this help message and exit
--parser PARSER, -p PARSER
Parser class. Default:
translating_parser.parser.TranslatingParser
--output-format OUTPUT_FORMAT, -f OUTPUT_FORMAT
Output format: json or yaml. Default: json
--verbose, -v Verbose output
To use the original Resolving Parser, use -p prance.ResolvingParser
.
$ PYTHONPATH=. pipenv run pytest