spec-first/connexion

Response validation enforces wrong type when paths have common prefix and parameter

Closed this issue · 4 comments

Description

Connexion v3 may be mis-matching paths if prefixes overlap? In my case, it chooses the wrong response type, so validation fails.

My openAPI spec has paths /user/{uid} and /user/all_roles. The response type for /user/{uid} is an object with field uid, the response type for /user/all_roles is a list of objects, each with field name. The openapi-spec-validator has no complaints about the spec. This worked fine in Connexion v2.

When running tox tests, I set Connexion app property validate_responses to True.

The test sends a request to /user/all_roles, Connexion returns status code 500 and internally raises an exception. Here's a log excerpt, I hope it is reasonably clear what's going on:

DEBUG    my.controller:controller.py:680 response [{'name': 'role name'}]
WARNING  connexion.validators.json:json.py:133 Validation error: [{'name': 'role name'}] is not of type 'object'
ERROR    connexion.middleware.exceptions:exceptions.py:79 NonConformingResponseBody(status_code=500, detail="Response body does not conform to specification. [{'name': 'role name'}] is not of type 'object'")

Trying to figure this out, I changed the role endpoint response to an object (not a list), and that gave me a further clue:

DEBUG    my.controller:controller.py:680 response {'name': 'role name'}
WARNING  connexion.validators.json:json.py:133 Validation error: 'uid' is a required property
ERROR    connexion.middleware.exceptions:exceptions.py:79 NonConformingResponseBody(status_code=500, detail="Response body does not conform to specification. 'uid' is a required property")

The uid field is defined for a user, but not for a role. So I'm guessing that apparently Connexion picked the response type for endpoint /usr/{uid} instead, possibly because of some bad path matching due to the common prefix and the path parameter?

Expected behaviour

Connexion matches the request path appropriately and uses the response type for /user/all_roles when responding toa request to that.

Actual behaviour

Connexion seems to feel that /user/all_roles matches the path pattern /user/{uid}, gets the response type for that endpoint, and validates the response against it.

Steps to reproduce

I have not yet worked up a SSCCE.

Additional info:

Python version 3.12
Connexion version 3.1.0

I searched the issues looking for a similar complaint to see if something was fixed, but found nothing.

I can workaround this by changing the paths so they don't share a prefix, for example changing the roles endpoint to /user_all_roles or something like that.

You could probably make a pretty strong case that paths should not overlap with a wildcard parameter and fixed path components. Now that I spotted this usage in my spec, I'm not really happy with it either. Still, the new v3 behavior is a regression from v2, and is yet another stumbling block in my migration path.

This PR seems related, but nobody described the situation of paths that differ in their last component, with fixed vs wildcard: #1736

Thanks for the report @chrisinmtown.

I would have expected this to get fixed with the route sorting though, so a minimal reproducible example would be nice to further investigate.

Today I tried to work up the SSCCE, and I could not reproduce the problem. I apologize for wasting your time.