openapi: Use serialized response codes instead of descriptive ones.

Openapi had descriptive response codes for endpoints with multiple
responses for same response code. But this does not fall in line
with openapi specifications. So change descriptive response codes
like "400_auth" and "400_anauth" to "400_0" and "400_1" for all
such endpoints. Also make the necessary changes in openapi.py so
as to be able to read the schema in such cases and generate example
in such cases.
This commit is contained in:
orientor
2020-04-17 22:46:43 +05:30
committed by Tim Abbott
parent 1131d136f3
commit bcb8def308
7 changed files with 39 additions and 28 deletions

View File

@@ -84,20 +84,20 @@ the `principals` argument, like so:
A typical successful JSON response may look like: A typical successful JSON response may look like:
{generate_code_example|/users/me/subscriptions:post|fixture(200_without_principals)} {generate_code_example|/users/me/subscriptions:post|fixture(200_0)}
A typical successful JSON response when the user is already subscribed to A typical successful JSON response when the user is already subscribed to
the streams specified: the streams specified:
{generate_code_example|/users/me/subscriptions:post|fixture(200_already_subscribed)} {generate_code_example|/users/me/subscriptions:post|fixture(200_1)}
A typical response for when the requesting user does not have access to A typical response for when the requesting user does not have access to
a private stream and `authorization_errors_fatal` is `True`: a private stream and `authorization_errors_fatal` is `True`:
{generate_code_example|/users/me/subscriptions:post|fixture(400_unauthorized_errors_fatal_true)} {generate_code_example|/users/me/subscriptions:post|fixture(400_0)}
A typical response for when the requesting user does not have access to A typical response for when the requesting user does not have access to
a private stream and `authorization_errors_fatal` is `False`: a private stream and `authorization_errors_fatal` is `False`:
{generate_code_example|/users/me/subscriptions:post|fixture(400_unauthorized_errors_fatal_false)} {generate_code_example|/users/me/subscriptions:post|fixture(400_1)}

View File

@@ -37,9 +37,9 @@ A typical successful JSON response may look like:
An example JSON response for when the specified message does not exist: An example JSON response for when the specified message does not exist:
{generate_code_example|/messages/{message_id}:delete|fixture(400_invalid_message)} {generate_code_example|/messages/{message_id}:delete|fixture(400_0)}
An example JSON response for when the user making the query does not An example JSON response for when the user making the query does not
have permission to delete the message: have permission to delete the message:
{generate_code_example|/messages/{message_id}:delete|fixture(400_not_admin)} {generate_code_example|/messages/{message_id}:delete|fixture(400_1)}

View File

@@ -35,9 +35,9 @@ A typical successful JSON response may look like:
An example JSON response for when an `add` operation is requested for a topic An example JSON response for when an `add` operation is requested for a topic
that has already been muted: that has already been muted:
{generate_code_example|/users/me/subscriptions/muted_topics:patch|fixture(400_topic_already_muted)} {generate_code_example|/users/me/subscriptions/muted_topics:patch|fixture(400_0)}
An example JSON response for when a `remove` operation is requested for a An example JSON response for when a `remove` operation is requested for a
topic that had not been previously muted: topic that had not been previously muted:
{generate_code_example|/users/me/subscriptions/muted_topics:patch|fixture(400_topic_not_muted)} {generate_code_example|/users/me/subscriptions/muted_topics:patch|fixture(400_1)}

View File

@@ -21,18 +21,18 @@ errors common to many endpoints:
A typical failed JSON response for when the API key is invalid: A typical failed JSON response for when the API key is invalid:
{generate_code_example|/rest-error-handling:post|fixture(400_invalid_api_key)} {generate_code_example|/rest-error-handling:post|fixture(400_0)}
## Missing request argument(s) ## Missing request argument(s)
A typical failed JSON response for when a required request argument A typical failed JSON response for when a required request argument
is not supplied: is not supplied:
{generate_code_example|/rest-error-handling:post|fixture(400_missing_request_argument_error)} {generate_code_example|/rest-error-handling:post|fixture(400_1)}
## User not authorized for query ## User not authorized for query
A typical failed JSON response for when the user is not authorized A typical failed JSON response for when the user is not authorized
for a query: for a query:
{generate_code_example|/rest-error-handling:post|fixture(400_user_not_authorized_error)} {generate_code_example|/rest-error-handling:post|fixture(400_2)}

View File

@@ -120,9 +120,9 @@ A typical successful JSON response may look like:
A typical failed JSON response for when a stream message is sent to a stream A typical failed JSON response for when a stream message is sent to a stream
that does not exist: that does not exist:
{generate_code_example|/messages:post|fixture(400_non_existing_stream)} {generate_code_example|/messages:post|fixture(400_0)}
A typical failed JSON response for when a private message is sent to a user A typical failed JSON response for when a private message is sent to a user
that does not exist: that does not exist:
{generate_code_example|/messages:post|fixture(400_non_existing_user)} {generate_code_example|/messages:post|fixture(400_1)}

View File

@@ -59,13 +59,25 @@ class SchemaError(Exception):
openapi_spec = OpenAPISpec(OPENAPI_SPEC_PATH) openapi_spec = OpenAPISpec(OPENAPI_SPEC_PATH)
def get_schema(endpoint: str, method: str, response: str) -> Dict[str, Any]:
if len(response) == 3:
schema = (openapi_spec.spec()['paths'][endpoint][method.lower()]['responses']
[response]['content']['application/json']['schema'])
return schema
else:
resp_code = int(response[4])
response = response[0:3]
schema = (openapi_spec.spec()['paths'][endpoint][method.lower()]['responses']
[response]['content']['application/json']['schema']["oneOf"][resp_code])
return schema
def get_openapi_fixture(endpoint: str, method: str, def get_openapi_fixture(endpoint: str, method: str,
response: Optional[str]='200') -> Dict[str, Any]: response: Optional[str]='200') -> Dict[str, Any]:
"""Fetch a fixture from the full spec object. """Fetch a fixture from the full spec object.
""" """
return (openapi_spec.spec()['paths'][endpoint][method.lower()]['responses'] if response is None:
[response]['content']['application/json']['schema'] response = '200'
['example']) return (get_schema(endpoint, method, response)['example'])
def get_openapi_paths() -> Set[str]: def get_openapi_paths() -> Set[str]:
return set(openapi_spec.spec()['paths'].keys()) return set(openapi_spec.spec()['paths'].keys())
@@ -88,8 +100,7 @@ def validate_against_openapi_schema(content: Dict[str, Any], endpoint: str,
"""Compare a "content" dict with the defined schema for a specific method """Compare a "content" dict with the defined schema for a specific method
in an endpoint. in an endpoint.
""" """
schema = (openapi_spec.spec()['paths'][endpoint][method.lower()]['responses'] schema = get_schema(endpoint, method, response)
[response]['content']['application/json']['schema'])
exclusion_list = (EXCLUDE_PROPERTIES.get(endpoint, {}).get(method, {}) exclusion_list = (EXCLUDE_PROPERTIES.get(endpoint, {}).get(method, {})
.get(response, [])) .get(response, []))

View File

@@ -62,7 +62,7 @@ def add_subscriptions(client):
# {code_example|end} # {code_example|end}
validate_against_openapi_schema(result, '/users/me/subscriptions', 'post', validate_against_openapi_schema(result, '/users/me/subscriptions', 'post',
'200_without_principals') '200_0')
# {code_example|start} # {code_example|start}
# To subscribe another user to a stream, you may pass in # To subscribe another user to a stream, you may pass in
@@ -87,7 +87,7 @@ def test_add_subscriptions_already_subscribed(client):
) )
validate_against_openapi_schema(result, '/users/me/subscriptions', 'post', validate_against_openapi_schema(result, '/users/me/subscriptions', 'post',
'200_already_subscribed') '200_1')
def test_authorization_errors_fatal(client, nonadmin_client): def test_authorization_errors_fatal(client, nonadmin_client):
# type: (Client, Client) -> None # type: (Client, Client) -> None
@@ -112,7 +112,7 @@ def test_authorization_errors_fatal(client, nonadmin_client):
) )
validate_against_openapi_schema(result, '/users/me/subscriptions', 'post', validate_against_openapi_schema(result, '/users/me/subscriptions', 'post',
'400_unauthorized_errors_fatal_false') '400_0')
result = nonadmin_client.add_subscriptions( result = nonadmin_client.add_subscriptions(
streams=[ streams=[
@@ -122,7 +122,7 @@ def test_authorization_errors_fatal(client, nonadmin_client):
) )
validate_against_openapi_schema(result, '/users/me/subscriptions', 'post', validate_against_openapi_schema(result, '/users/me/subscriptions', 'post',
'400_unauthorized_errors_fatal_true') '400_1')
@openapi_test_function("/users/{email}/presence:get") @openapi_test_function("/users/{email}/presence:get")
def get_user_presence(client): def get_user_presence(client):
@@ -413,7 +413,7 @@ def test_user_not_authorized_error(nonadmin_client):
# type: (Client) -> None # type: (Client) -> None
result = nonadmin_client.get_streams(include_all_active=True) result = nonadmin_client.get_streams(include_all_active=True)
validate_against_openapi_schema(result, '/rest-error-handling', 'post', '400_user_not_authorized_error') validate_against_openapi_schema(result, '/rest-error-handling', 'post', '400_2')
def get_subscribers(client): def get_subscribers(client):
# type: (Client) -> None # type: (Client) -> None
@@ -718,7 +718,7 @@ def test_nonexistent_stream_error(client):
result = client.send_message(request) result = client.send_message(request)
validate_against_openapi_schema(result, '/messages', 'post', validate_against_openapi_schema(result, '/messages', 'post',
'400_non_existing_stream') '400_0')
def test_private_message_invalid_recipient(client): def test_private_message_invalid_recipient(client):
# type: (Client) -> None # type: (Client) -> None
@@ -730,7 +730,7 @@ def test_private_message_invalid_recipient(client):
result = client.send_message(request) result = client.send_message(request)
validate_against_openapi_schema(result, '/messages', 'post', validate_against_openapi_schema(result, '/messages', 'post',
'400_non_existing_user') '400_1')
@openapi_test_function("/messages/{message_id}:patch") @openapi_test_function("/messages/{message_id}:patch")
def update_message(client, message_id): def update_message(client, message_id):
@@ -804,7 +804,7 @@ def test_delete_message_edit_permission_error(client, nonadmin_client):
result = nonadmin_client.delete_message(result['id']) result = nonadmin_client.delete_message(result['id'])
validate_against_openapi_schema(result, '/messages/{message_id}', 'delete', validate_against_openapi_schema(result, '/messages/{message_id}', 'delete',
'400_not_admin') '400_1')
@openapi_test_function("/messages/{message_id}/history:get") @openapi_test_function("/messages/{message_id}/history:get")
def get_message_history(client, message_id): def get_message_history(client, message_id):
@@ -1098,13 +1098,13 @@ def update_user_group_members(client, group_id):
def test_invalid_api_key(client_with_invalid_key): def test_invalid_api_key(client_with_invalid_key):
# type: (Client) -> None # type: (Client) -> None
result = client_with_invalid_key.list_subscriptions() result = client_with_invalid_key.list_subscriptions()
validate_against_openapi_schema(result, '/rest-error-handling', 'post', '400_invalid_api_key') validate_against_openapi_schema(result, '/rest-error-handling', 'post', '400_0')
def test_missing_request_argument(client): def test_missing_request_argument(client):
# type: (Client) -> None # type: (Client) -> None
result = client.render_message({}) result = client.render_message({})
validate_against_openapi_schema(result, '/rest-error-handling', 'post', '400_missing_request_argument_error') validate_against_openapi_schema(result, '/rest-error-handling', 'post', '400_1')
def test_invalid_stream_error(client): def test_invalid_stream_error(client):