-
Notifications
You must be signed in to change notification settings - Fork 0
Feat | Add support for OpenAPI 3.1 [CU-86b7bdpnw] #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
matiasperrone-exo
wants to merge
1
commit into
master
Choose a base branch
from
feat/openapi---3.1
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+173
−8
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,120 @@ | ||
| import json | ||
|
|
||
| import yaml | ||
| from django.test import TestCase | ||
| from django.urls import reverse | ||
|
|
||
|
|
||
| class OpenAPISchemaTests(TestCase): | ||
|
|
||
| SCHEMA_URL = reverse('openapi-schema') | ||
| SCHEMA_URL_JSON = SCHEMA_URL + '?format=json' | ||
| SCHEMA_URL_YAML = SCHEMA_URL + '?format=yaml' | ||
|
|
||
| def _get_schema(self): | ||
| response = self.client.get(self.SCHEMA_URL_JSON) | ||
| self.assertEqual(response.status_code, 200) | ||
| return json.loads(response.content) | ||
|
|
||
| def test_schema_default_format_returns_valid_yaml_on_default_url(self): | ||
| response = self.client.get(self.SCHEMA_URL) | ||
| self.assertEqual(response.status_code, 200) | ||
| schema = yaml.safe_load(response.content) | ||
| self.assertIn('openapi', schema) | ||
| self.assertIn('paths', schema) | ||
|
|
||
| def test_schema_default_format_returns_valid_yaml(self): | ||
| response = self.client.get(self.SCHEMA_URL_YAML) | ||
| self.assertEqual(response.status_code, 200) | ||
| schema = yaml.safe_load(response.content) | ||
| self.assertIn('openapi', schema) | ||
| self.assertIn('paths', schema) | ||
|
|
||
| def test_schema_returns_200(self): | ||
| response = self.client.get(self.SCHEMA_URL_JSON) | ||
| self.assertEqual(response.status_code, 200) | ||
|
|
||
| def test_schema_is_valid_json(self): | ||
| schema = self._get_schema() | ||
| self.assertIn('openapi', schema) | ||
| self.assertIn('paths', schema) | ||
| self.assertIn('info', schema) | ||
|
|
||
| def test_schema_version_is_3_1(self): | ||
| schema = self._get_schema() | ||
| self.assertTrue(schema['openapi'].startswith('3.1')) | ||
|
|
||
| def test_schema_info(self): | ||
| schema = self._get_schema() | ||
| self.assertEqual(schema['info']['title'], 'Marketing API') | ||
|
|
||
| def test_schema_contains_public_and_private_tags(self): | ||
| schema = self._get_schema() | ||
| tag_names = [t['name'] for t in schema.get('tags', [])] | ||
| self.assertIn('Public', tag_names) | ||
| self.assertIn('Private', tag_names) | ||
|
|
||
| def test_schema_contains_oauth2_security_scheme(self): | ||
| schema = self._get_schema() | ||
| security_schemes = schema.get('components', {}).get('securitySchemes', {}) | ||
| self.assertIn('OAuth2', security_schemes) | ||
| self.assertEqual(security_schemes['OAuth2']['type'], 'oauth2') | ||
|
|
||
| def test_schema_has_paths(self): | ||
| schema = self._get_schema() | ||
| self.assertGreater(len(schema['paths']), 0) | ||
|
|
||
| def test_public_endpoints_have_no_security(self): | ||
| schema = self._get_schema() | ||
| for path, methods in schema['paths'].items(): | ||
| if path.startswith('/api/public/'): | ||
| for method, spec in methods.items(): | ||
| if method in ('get', 'post', 'put', 'patch', 'delete'): | ||
| self.assertEqual( | ||
| spec.get('security', []), | ||
| [], | ||
| f'{method.upper()} {path} should have empty security' | ||
| ) | ||
|
|
||
|
|
||
| def test_admin_endpoints_not_in_schema(self): | ||
| schema = self._get_schema() | ||
| for path in schema['paths']: | ||
| self.assertFalse( | ||
| path.startswith('/admin'), | ||
| f'Admin endpoint {path} should not appear in schema' | ||
| ) | ||
|
|
||
| def test_all_paths_are_under_api_prefix(self): | ||
| schema = self._get_schema() | ||
| for path in schema['paths']: | ||
| self.assertTrue( | ||
| path.startswith('/api/'), | ||
| f'Path {path} should be under /api/ prefix' | ||
| ) | ||
|
|
||
|
|
||
| class SwaggerUITests(TestCase): | ||
|
|
||
| DOCS_URL = reverse('swagger-ui') | ||
|
|
||
| def test_swagger_ui_returns_200(self): | ||
| response = self.client.get(self.DOCS_URL) | ||
| self.assertEqual(response.status_code, 200) | ||
|
|
||
| def test_swagger_ui_contains_html(self): | ||
| response = self.client.get(self.DOCS_URL) | ||
| self.assertIn('text/html', response['Content-Type']) | ||
|
|
||
|
|
||
| class RedocTests(TestCase): | ||
|
|
||
| DOCS_URL = reverse('redoc') | ||
|
|
||
| def test_redoc_returns_200(self): | ||
| response = self.client.get(self.DOCS_URL) | ||
| self.assertEqual(response.status_code, 200) | ||
|
|
||
| def test_redoc_contains_html(self): | ||
| response = self.client.get(self.DOCS_URL) | ||
| self.assertIn('text/html', response['Content-Type']) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| def custom_postprocessing_hook(result, generator, request, public): | ||
| for path, methods in result.get('paths', {}).items(): | ||
| is_public = path.startswith('/api/public/') | ||
matiasperrone-exo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| tag = 'Public' if is_public else 'Private' | ||
| for method, operation in methods.items(): | ||
| if not isinstance(operation, dict): | ||
| continue | ||
| operation['tags'] = [tag] | ||
matiasperrone-exo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if is_public: | ||
| operation['security'] = [] | ||
matiasperrone-exo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return result | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -66,3 +66,4 @@ uritemplate==4.2.0 | |
| urllib3==2.5.0 | ||
| Werkzeug==3.1.4 | ||
| wrapt==2.0.1 | ||
| drf-spectacular==0.28.0 | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.