core-api / python-openapi-codec

An OpenAPI codec for Core API.
Other
33 stars 35 forks source link

Provide Hook or Flag for _get_links Behaviour #45

Open mverteuil opened 6 years ago

mverteuil commented 6 years ago

There is a bit of cleverness in _get_links that looks for a common prefix and extracts it into tags. This behaviour causes unpredictable results in the encoded schema if a variety of top level items used in different contexts are not displayed to a user based on their permissions.

For example:

User A has access to:

User B has access to:

The result is that User A's schema will have different operationId values than User B, which means my client code breaks depending on which user is accessing the encoded spec.

The default implementation in SchemaGenerator will cut off the /api prefix which is fine, but the problem stems from the fact that User B does not have access to /api/protein/beef.

This means the resulting operationIds and tags for User A are:

url tags operationId
/api/vegetables/seedless/ vegetables seedless_create
/api/vegetables/seedless/ vegetables seedless_list
/api/vegetables/seeded/ vegetables seeded_create
/api/vegetables/seeded/ vegetables seeded_list
/api/protein/beef/ protein beef_create
/api/protein/beef/ protein beef_list

However User B has:

url tags operationId
/api/vegetables/seedless/ seedless seedless_create
/api/vegetables/seedless/ seedless seedless_list
/api/vegetables/seeded/ seeded seeded_create
/api/vegetables/seeded/ seeded seeded_list

If I try to use the Swagger JS client, due to the variations in the schema, the path changes depending on which user is logged in which is extremely frustrating. This should be configurable by hook or flag, as I'm currently forced to leverage mock.patch to replace openapi_codec.encode._get_links which is horribly fragile and obviously undesired in production code.

For reference, my current solution is to eliminate the section where tags are determined which allows me to route all of my operations through a common operationId, regardless of the level of access the request user has.

def _get_links(document):
    """
    Monkey patch for openapi_codec.encode._get_links

    Implementation removes cleverness in openapi_codec.encode._get_links which tries to reduce
    the size of operation names by removing what it assumes to be redundancies.

    This is not suitable for our case, since the contents of our schemata vary depending on the
    access level of the request user.

    This patch may be applied with a context manager during OpenAPI document rendering.
    """
    # Extract all the links from the first or second level of the document.
    links = []
    for keys, link in get_links_from_document(document):
        operation_id = '_'.join(keys)
        links.append((operation_id, link, []))
    return links