Skip to content

Commit 5f95501

Browse files
authored
Upgrade OpenAPI spec to v3
Merge pull request #989 from openfisca/openapi-v3
2 parents 78c0d5f + be3dee5 commit 5f95501

6 files changed

Lines changed: 350 additions & 271 deletions

File tree

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# Changelog
22

3+
# 38.0.0 [#989](https://github.com/openfisca/openfisca-core/pull/989)
4+
5+
#### New Features
6+
7+
- Upgrade OpenAPI specification of the API to v3 from Swagger v2.
8+
- Continuously validate OpenAPI specification.
9+
10+
#### Breaking changes
11+
12+
- Drop support for OpenAPI specification v2 and prior.
13+
- 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)).
14+
315
### 37.0.2 [#1170](https://github.com/openfisca/openfisca-core/pull/1170)
416

517
#### Technical changes

openfisca_web_api/app.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,13 @@ def get_entities():
118118

119119
@app.route('/spec')
120120
def get_spec():
121+
scheme = request.environ["wsgi.url_scheme"]
122+
host = request.host
123+
url = f"{scheme}://{host}"
124+
121125
return jsonify({
122-
**data['openAPI_spec'],
123-
**{'host': request.host},
124-
**{'schemes': [request.environ['wsgi.url_scheme']]}
126+
**data["openAPI_spec"],
127+
**{"servers": [{"url": url}]},
125128
})
126129

127130
def handle_invalid_json(error):

openfisca_web_api/loader/spec.py

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,19 @@ def build_openAPI_specification(api_data):
1818
file = open(OPEN_API_CONFIG_FILE, 'r')
1919
spec = yaml.safe_load(file)
2020
country_package_name = api_data['country_package_metadata']['name'].title()
21+
country_package_version = api_data['country_package_metadata']['version']
2122
dpath.util.new(spec, 'info/title', spec['info']['title'].replace("{COUNTRY_PACKAGE_NAME}", country_package_name))
2223
dpath.util.new(spec, 'info/description', spec['info']['description'].replace("{COUNTRY_PACKAGE_NAME}", country_package_name))
23-
dpath.util.new(spec, 'info/version', api_data['country_package_metadata']['version'])
24+
dpath.util.new(spec, 'info/version', spec['info']['version'].replace("{COUNTRY_PACKAGE_VERSION}", country_package_version))
2425

2526
for entity in tax_benefit_system.entities:
2627
name = entity.key.title()
27-
spec['definitions'][name] = get_entity_json_schema(entity, tax_benefit_system)
28+
spec['components']['schemas'][name] = get_entity_json_schema(entity, tax_benefit_system)
2829

2930
situation_schema = get_situation_json_schema(tax_benefit_system)
30-
dpath.util.new(spec, 'definitions/SituationInput', situation_schema)
31-
dpath.util.new(spec, 'definitions/SituationOutput', situation_schema.copy())
32-
dpath.util.new(spec, 'definitions/Trace/properties/entitiesDescription/properties', {
31+
dpath.util.new(spec, 'components/schemas/SituationInput', situation_schema)
32+
dpath.util.new(spec, 'components/schemas/SituationOutput', situation_schema.copy())
33+
dpath.util.new(spec, 'components/schemas/Trace/properties/entitiesDescription/properties', {
3334
entity.plural: {'type': 'array', 'items': {"type": "string"}}
3435
for entity in tax_benefit_system.entities
3536
})
@@ -42,24 +43,24 @@ def build_openAPI_specification(api_data):
4243
parameter_example = api_data['parameters'][parameter_path]
4344
else:
4445
parameter_example = next(iter(api_data['parameters'].values()))
45-
dpath.util.new(spec, 'definitions/Parameter/example', parameter_example)
46+
dpath.util.new(spec, 'components/schemas/Parameter/example', parameter_example)
4647

4748
if tax_benefit_system.open_api_config.get('variable_example'):
4849
variable_example = api_data['variables'][tax_benefit_system.open_api_config['variable_example']]
4950
else:
5051
variable_example = next(iter(api_data['variables'].values()))
51-
dpath.util.new(spec, 'definitions/Variable/example', variable_example)
52+
dpath.util.new(spec, 'components/schemas/Variable/example', variable_example)
5253

5354
if tax_benefit_system.open_api_config.get('simulation_example'):
5455
simulation_example = tax_benefit_system.open_api_config['simulation_example']
55-
dpath.util.new(spec, 'definitions/SituationInput/example', simulation_example)
56-
dpath.util.new(spec, 'definitions/SituationOutput/example', handlers.calculate(tax_benefit_system, deepcopy(simulation_example))) # calculate has side-effects
57-
dpath.util.new(spec, 'definitions/Trace/example', handlers.trace(tax_benefit_system, simulation_example))
56+
dpath.util.new(spec, 'components/schemas/SituationInput/example', simulation_example)
57+
dpath.util.new(spec, 'components/schemas/SituationOutput/example', handlers.calculate(tax_benefit_system, deepcopy(simulation_example))) # calculate has side-effects
58+
dpath.util.new(spec, 'components/schemas/Trace/example', handlers.trace(tax_benefit_system, simulation_example))
5859
else:
5960
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)
60-
dpath.util.new(spec, 'definitions/SituationInput/example', message)
61-
dpath.util.new(spec, 'definitions/SituationOutput/example', message)
62-
dpath.util.new(spec, 'definitions/Trace/example', message)
61+
dpath.util.new(spec, 'components/schemas/SituationInput/example', message)
62+
dpath.util.new(spec, 'components/schemas/SituationOutput/example', message)
63+
dpath.util.new(spec, 'components/schemas/Trace/example', message)
6364
return spec
6465

6566

@@ -115,7 +116,7 @@ def get_situation_json_schema(tax_benefit_system):
115116
entity.plural: {
116117
'type': 'object',
117118
'additionalProperties': {
118-
"$ref": "#/definitions/{}".format(entity.key.title())
119+
"$ref": "#/components/schemas/{}".format(entity.key.title())
119120
}
120121
}
121122
for entity in tax_benefit_system.entities

0 commit comments

Comments
 (0)