Files
recipes/cookbook/helper/drf_spectacular_hooks.py
2024-04-22 19:33:09 +02:00

39 lines
2.8 KiB
Python

# custom processing for schema
# reason: DRF writable nested needs ID's to decide if a nested object should be created or updated
# the API schema/client make ID's read only by default and strips them entirely in request objects (with COMPONENT_SPLIT_REQUEST enabled)
# change request objects (schema ends with Request) and response objects (just model name) to the following:
# response objects: id field is required but read only
# request objects: id field is optional but writable/included
# WARNING: COMPONENT_SPLIT_REQUEST must be enabled, if not schemas might be wrong
def custom_postprocessing_hook(result, generator, request, public):
for c in result['components']['schemas'].keys():
# handle schemas used by the client to do requests on the server
if c.strip().endswith('Request'):
# check if request schema has a corresponding response schema to avoid changing request schemas for models that end with the word Request
response_schema = None
if c.strip().replace('Request', '') in result['components']['schemas'].keys():
response_schema = c.strip().replace('Request', '')
elif c.strip().startswith('Patched') and c.strip().replace('Request', '').replace('Patched', '', 1) in result['components']['schemas'].keys():
response_schema = c.strip().replace('Request', '').replace('Patched', '', 1)
# if response schema exist update request schema to include writable, optional id
if response_schema and 'id' in result['components']['schemas'][response_schema]['properties']:
if 'id' not in result['components']['schemas'][c]['properties']:
result['components']['schemas'][c]['properties']['id'] = {'readOnly': False, 'type': 'integer'}
# this is probably never the case but make sure ID is not required anyway
if 'required' in result['components']['schemas'][c] and 'id' in result['components']['schemas'][c]['required']:
result['components']['schemas'][c]['required'].remove('id')
# handle all schemas returned by the server to the client
else:
if 'properties' in result['components']['schemas'][c] and 'id' in result['components']['schemas'][c]['properties']:
# make ID field not read only so it's not stripped from the request on the client
result['components']['schemas'][c]['properties']['id']['readOnly'] = True
# make ID field required because if an object has an id it should also always be returned
if 'required' not in result['components']['schemas'][c]:
result['components']['schemas'][c]['required'] = ['id']
else:
result['components']['schemas'][c]['required'].append('id')
return result