Skip to content

Commit 964b7e6

Browse files
committed
OAS 3.1
1 parent 6e4180b commit 964b7e6

File tree

11 files changed

+2207
-18
lines changed

11 files changed

+2207
-18
lines changed

drf_spectacular/hooks.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,10 @@ def create_enum_component(name, schema):
134134
if '' in prop_enum_original_list:
135135
components.append(create_enum_component('BlankEnum', schema={'enum': ['']}))
136136
if None in prop_enum_original_list:
137-
components.append(create_enum_component('NullEnum', schema={'enum': [None]}))
137+
if spectacular_settings.OAS_VERSION.startswith('3.1'):
138+
components.append(create_enum_component('NullEnum', schema={'type': 'null'}))
139+
else:
140+
components.append(create_enum_component('NullEnum', schema={'enum': [None]}))
138141

139142
if len(components) == 1:
140143
prop_schema.update(components[0].ref)

drf_spectacular/openapi.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -956,6 +956,7 @@ def _get_serializer_field_meta(self, field, direction):
956956
if field.write_only:
957957
meta['writeOnly'] = True
958958
if field.allow_null:
959+
# this will be converted later in case of OAS 3.1
959960
meta['nullable'] = True
960961
if isinstance(field, serializers.CharField) and not field.allow_blank:
961962
# blank check only applies to inbound requests

drf_spectacular/plumbing.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,7 @@ def build_root_object(paths, components, version):
469469
else:
470470
version = settings.VERSION or version or ''
471471
root = {
472-
'openapi': '3.0.3',
472+
'openapi': settings.OAS_VERSION,
473473
'info': {
474474
'title': settings.TITLE,
475475
'version': version,
@@ -507,6 +507,18 @@ def safe_ref(schema):
507507

508508

509509
def append_meta(schema, meta):
510+
if spectacular_settings.OAS_VERSION.startswith('3.1'):
511+
schema_nullable = meta.pop('nullable', None)
512+
meta_nullable = schema.pop('nullable', None)
513+
514+
if schema_nullable or meta_nullable:
515+
if 'type' in schema:
516+
schema['type'] = [schema['type'], 'null']
517+
elif '$ref' in schema:
518+
schema = {'oneOf': [schema, {'type': 'null'}]}
519+
else:
520+
assert False, 'Invalid nullable case'
521+
510522
return safe_ref({**schema, **meta})
511523

512524

drf_spectacular/settings.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@
4444
# accurately modeled when request and response components are separated.
4545
'ENFORCE_NON_BLANK_FIELDS': False,
4646

47+
#
48+
'OAS_VERSION': '3.0.3',
49+
4750
# Configuration for serving a schema subset with SpectacularAPIView
4851
'SERVE_URLCONF': None,
4952
# complete public schema or a subset based on the requesting user

drf_spectacular/validation/__init__.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,28 @@
33

44
import jsonschema
55

6-
JSON_SCHEMA_SPEC_PATH = os.path.join(os.path.dirname(__file__), 'openapi3_schema.json')
7-
86

97
def validate_schema(api_schema):
108
"""
119
Validate generated API schema against OpenAPI 3.0.X json schema specification.
1210
Note: On conflict, the written specification always wins over the json schema.
1311
1412
OpenApi3 schema specification taken from:
13+
1514
https://github.com/OAI/OpenAPI-Specification/blob/master/schemas/v3.0/schema.json
16-
https://github.com/OAI/OpenAPI-Specification/blob/6d17b631fff35186c495b9e7d340222e19d60a71/schemas/v3.0/schema.json
15+
https://github.com/OAI/OpenAPI-Specification/blob/9dff244e5708fbe16e768738f4f17cf3fddf4066/schemas/v3.0/schema.json
16+
17+
https://github.com/OAI/OpenAPI-Specification/blob/main/schemas/v3.1/schema.json
18+
https://github.com/OAI/OpenAPI-Specification/blob/9dff244e5708fbe16e768738f4f17cf3fddf4066/schemas/v3.1/schema.json
1719
"""
18-
with open(JSON_SCHEMA_SPEC_PATH) as fh:
20+
if api_schema['openapi'].startswith("3.0"):
21+
schema_spec_path = os.path.join(os.path.dirname(__file__), 'openapi3.0_schema.json')
22+
elif api_schema['openapi'].startswith("3.1"):
23+
schema_spec_path = os.path.join(os.path.dirname(__file__), 'openapi3.1_schema.json')
24+
else:
25+
raise RuntimeError('No validation specification available')
26+
27+
with open(schema_spec_path) as fh:
1928
openapi3_schema_spec = json.load(fh)
2029

2130
# coerce any remnants of objects to basic types

drf_spectacular/validation/openapi3_schema.json renamed to drf_spectacular/validation/openapi_3_0_schema.json

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
2-
"id": "https://spec.openapis.org/oas/3.0/schema/2019-04-02",
2+
"id": "https://spec.openapis.org/oas/3.0/schema/2021-09-28",
33
"$schema": "http://json-schema.org/draft-04/schema#",
4-
"description": "Validation schema for OpenAPI Specification 3.0.X.",
4+
"description": "The description of OpenAPI v3.0.x documents, as defined by https://spec.openapis.org/oas/v3.0.3",
55
"type": "object",
66
"required": [
77
"openapi",
@@ -1358,9 +1358,8 @@
13581358
"description": "Bearer",
13591359
"properties": {
13601360
"scheme": {
1361-
"enum": [
1362-
"bearer"
1363-
]
1361+
"type": "string",
1362+
"pattern": "^[Bb][Ee][Aa][Rr][Ee][Rr]$"
13641363
}
13651364
}
13661365
},
@@ -1374,9 +1373,8 @@
13741373
"properties": {
13751374
"scheme": {
13761375
"not": {
1377-
"enum": [
1378-
"bearer"
1379-
]
1376+
"type": "string",
1377+
"pattern": "^[Bb][Ee][Aa][Rr][Ee][Rr]$"
13801378
}
13811379
}
13821380
}
@@ -1489,7 +1487,8 @@
14891487
"PasswordOAuthFlow": {
14901488
"type": "object",
14911489
"required": [
1492-
"tokenUrl"
1490+
"tokenUrl",
1491+
"scopes"
14931492
],
14941493
"properties": {
14951494
"tokenUrl": {
@@ -1516,7 +1515,8 @@
15161515
"ClientCredentialsFlow": {
15171516
"type": "object",
15181517
"required": [
1519-
"tokenUrl"
1518+
"tokenUrl",
1519+
"scopes"
15201520
],
15211521
"properties": {
15221522
"tokenUrl": {
@@ -1544,7 +1544,8 @@
15441544
"type": "object",
15451545
"required": [
15461546
"authorizationUrl",
1547-
"tokenUrl"
1547+
"tokenUrl",
1548+
"scopes"
15481549
],
15491550
"properties": {
15501551
"authorizationUrl": {
@@ -1628,7 +1629,14 @@
16281629
"headers": {
16291630
"type": "object",
16301631
"additionalProperties": {
1631-
"$ref": "#/definitions/Header"
1632+
"oneOf": [
1633+
{
1634+
"$ref": "#/definitions/Header"
1635+
},
1636+
{
1637+
"$ref": "#/definitions/Reference"
1638+
}
1639+
]
16321640
}
16331641
},
16341642
"style": {
@@ -1648,6 +1656,10 @@
16481656
"default": false
16491657
}
16501658
},
1659+
"patternProperties": {
1660+
"^x-": {
1661+
}
1662+
},
16511663
"additionalProperties": false
16521664
}
16531665
}

0 commit comments

Comments
 (0)