Skip to content

Commit

Permalink
Upgrade OpenAPI spec to v3
Browse files Browse the repository at this point in the history
Merge pull request #989 from openfisca/openapi-v3
  • Loading branch information
bonjourmauko authored Dec 12, 2022
2 parents 78c0d5f + be3dee5 commit 5f95501
Show file tree
Hide file tree
Showing 6 changed files with 350 additions and 271 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Changelog

# 38.0.0 [#989](https://github.com/openfisca/openfisca-core/pull/989)

#### New Features

- Upgrade OpenAPI specification of the API to v3 from Swagger v2.
- Continuously validate OpenAPI specification.

#### Breaking changes

- Drop support for OpenAPI specification v2 and prior.
- Users relying on OpenAPI v2 can use [Swagger Converter](https://converter.swagger.io/api/convert?url=OAS2_YAML_OR_JSON_URL) to migrate ([example](https://web.archive.org/web/20221103230822/https://converter.swagger.io/api/convert?url=https://api.demo.openfisca.org/latest/spec)).

### 37.0.2 [#1170](https://github.com/openfisca/openfisca-core/pull/1170)

#### Technical changes
Expand Down
9 changes: 6 additions & 3 deletions openfisca_web_api/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,13 @@ def get_entities():

@app.route('/spec')
def get_spec():
scheme = request.environ["wsgi.url_scheme"]
host = request.host
url = f"{scheme}://{host}"

return jsonify({
**data['openAPI_spec'],
**{'host': request.host},
**{'schemes': [request.environ['wsgi.url_scheme']]}
**data["openAPI_spec"],
**{"servers": [{"url": url}]},
})

def handle_invalid_json(error):
Expand Down
29 changes: 15 additions & 14 deletions openfisca_web_api/loader/spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,19 @@ def build_openAPI_specification(api_data):
file = open(OPEN_API_CONFIG_FILE, 'r')
spec = yaml.safe_load(file)
country_package_name = api_data['country_package_metadata']['name'].title()
country_package_version = api_data['country_package_metadata']['version']
dpath.util.new(spec, 'info/title', spec['info']['title'].replace("{COUNTRY_PACKAGE_NAME}", country_package_name))
dpath.util.new(spec, 'info/description', spec['info']['description'].replace("{COUNTRY_PACKAGE_NAME}", country_package_name))
dpath.util.new(spec, 'info/version', api_data['country_package_metadata']['version'])
dpath.util.new(spec, 'info/version', spec['info']['version'].replace("{COUNTRY_PACKAGE_VERSION}", country_package_version))

for entity in tax_benefit_system.entities:
name = entity.key.title()
spec['definitions'][name] = get_entity_json_schema(entity, tax_benefit_system)
spec['components']['schemas'][name] = get_entity_json_schema(entity, tax_benefit_system)

situation_schema = get_situation_json_schema(tax_benefit_system)
dpath.util.new(spec, 'definitions/SituationInput', situation_schema)
dpath.util.new(spec, 'definitions/SituationOutput', situation_schema.copy())
dpath.util.new(spec, 'definitions/Trace/properties/entitiesDescription/properties', {
dpath.util.new(spec, 'components/schemas/SituationInput', situation_schema)
dpath.util.new(spec, 'components/schemas/SituationOutput', situation_schema.copy())
dpath.util.new(spec, 'components/schemas/Trace/properties/entitiesDescription/properties', {
entity.plural: {'type': 'array', 'items': {"type": "string"}}
for entity in tax_benefit_system.entities
})
Expand All @@ -42,24 +43,24 @@ def build_openAPI_specification(api_data):
parameter_example = api_data['parameters'][parameter_path]
else:
parameter_example = next(iter(api_data['parameters'].values()))
dpath.util.new(spec, 'definitions/Parameter/example', parameter_example)
dpath.util.new(spec, 'components/schemas/Parameter/example', parameter_example)

if tax_benefit_system.open_api_config.get('variable_example'):
variable_example = api_data['variables'][tax_benefit_system.open_api_config['variable_example']]
else:
variable_example = next(iter(api_data['variables'].values()))
dpath.util.new(spec, 'definitions/Variable/example', variable_example)
dpath.util.new(spec, 'components/schemas/Variable/example', variable_example)

if tax_benefit_system.open_api_config.get('simulation_example'):
simulation_example = tax_benefit_system.open_api_config['simulation_example']
dpath.util.new(spec, 'definitions/SituationInput/example', simulation_example)
dpath.util.new(spec, 'definitions/SituationOutput/example', handlers.calculate(tax_benefit_system, deepcopy(simulation_example))) # calculate has side-effects
dpath.util.new(spec, 'definitions/Trace/example', handlers.trace(tax_benefit_system, simulation_example))
dpath.util.new(spec, 'components/schemas/SituationInput/example', simulation_example)
dpath.util.new(spec, 'components/schemas/SituationOutput/example', handlers.calculate(tax_benefit_system, deepcopy(simulation_example))) # calculate has side-effects
dpath.util.new(spec, 'components/schemas/Trace/example', handlers.trace(tax_benefit_system, simulation_example))
else:
message = "No simulation example has been defined for this tax and benefit system. If you are the maintainer of {}, you can define an example by following this documentation: https://openfisca.org/doc/openfisca-web-api/config-openapi.html".format(country_package_name)
dpath.util.new(spec, 'definitions/SituationInput/example', message)
dpath.util.new(spec, 'definitions/SituationOutput/example', message)
dpath.util.new(spec, 'definitions/Trace/example', message)
dpath.util.new(spec, 'components/schemas/SituationInput/example', message)
dpath.util.new(spec, 'components/schemas/SituationOutput/example', message)
dpath.util.new(spec, 'components/schemas/Trace/example', message)
return spec


Expand Down Expand Up @@ -115,7 +116,7 @@ def get_situation_json_schema(tax_benefit_system):
entity.plural: {
'type': 'object',
'additionalProperties': {
"$ref": "#/definitions/{}".format(entity.key.title())
"$ref": "#/components/schemas/{}".format(entity.key.title())
}
}
for entity in tax_benefit_system.entities
Expand Down
Loading

0 comments on commit 5f95501

Please sign in to comment.