drf-to-mkdoc 0.2.1__py3-none-any.whl → 0.2.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of drf-to-mkdoc might be problematic. Click here for more details.
- drf_to_mkdoc/conf/defaults.py +1 -0
- drf_to_mkdoc/conf/settings.py +0 -2
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/form-manager.js +172 -0
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/main.js +22 -0
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/modal.js +79 -0
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/request-executor.js +111 -0
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/suggestions.js +216 -0
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/tabs.js +34 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/buttons.css +71 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/fab.css +47 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/form.css +124 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/key-value.css +161 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/main.css +57 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/modal.css +112 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/response.css +158 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/tabs.css +62 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/variables.css +38 -0
- drf_to_mkdoc/templates/endpoints/detail/base.html +35 -0
- drf_to_mkdoc/templates/endpoints/detail/path_parameters.html +8 -0
- drf_to_mkdoc/templates/endpoints/detail/query_parameters.html +36 -0
- drf_to_mkdoc/templates/endpoints/detail/request_body.html +10 -0
- drf_to_mkdoc/templates/endpoints/detail/responses.html +18 -0
- drf_to_mkdoc/templates/endpoints/list/base.html +23 -0
- drf_to_mkdoc/templates/endpoints/list/endpoint_card.html +18 -0
- drf_to_mkdoc/templates/endpoints/list/filter_section.html +16 -0
- drf_to_mkdoc/templates/endpoints/list/filters/app.html +8 -0
- drf_to_mkdoc/templates/endpoints/list/filters/method.html +12 -0
- drf_to_mkdoc/templates/endpoints/list/filters/path.html +5 -0
- drf_to_mkdoc/templates/endpoints/list/filters/search.html +9 -0
- drf_to_mkdoc/templates/model_detail/base.html +34 -0
- drf_to_mkdoc/templates/model_detail/choices.html +12 -0
- drf_to_mkdoc/templates/model_detail/fields.html +11 -0
- drf_to_mkdoc/templates/model_detail/meta.html +6 -0
- drf_to_mkdoc/templates/model_detail/methods.html +9 -0
- drf_to_mkdoc/templates/model_detail/relationships.html +8 -0
- drf_to_mkdoc/templates/models_index.html +24 -0
- drf_to_mkdoc/templates/try-out/fab.html +4 -0
- drf_to_mkdoc/templates/try-out/form.html +113 -0
- drf_to_mkdoc/templates/try-out/main.html +4 -0
- drf_to_mkdoc/templates/try-out/modal.html +14 -0
- drf_to_mkdoc/templates/try-out/response-modal.html +20 -0
- drf_to_mkdoc/templatetags/custom_filters.py +148 -0
- drf_to_mkdoc/utils/commons/schema_utils.py +5 -14
- drf_to_mkdoc/utils/endpoint_detail_generator.py +201 -171
- drf_to_mkdoc/utils/endpoint_list_generator.py +58 -193
- drf_to_mkdoc/utils/extractors/query_parameter_extractors.py +0 -15
- drf_to_mkdoc/utils/model_detail_generator.py +22 -202
- drf_to_mkdoc/utils/model_list_generator.py +26 -44
- drf_to_mkdoc/utils/schema.py +1 -1
- {drf_to_mkdoc-0.2.1.dist-info → drf_to_mkdoc-0.2.3.dist-info}/METADATA +1 -1
- drf_to_mkdoc-0.2.3.dist-info/RECORD +103 -0
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out-sidebar.js +0 -879
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/try-out-sidebar.css +0 -728
- drf_to_mkdoc/utils/md_generators/__init__.py +0 -0
- drf_to_mkdoc/utils/md_generators/query_parameters_generators.py +0 -72
- drf_to_mkdoc-0.2.1.dist-info/RECORD +0 -67
- {drf_to_mkdoc-0.2.1.dist-info → drf_to_mkdoc-0.2.3.dist-info}/WHEEL +0 -0
- {drf_to_mkdoc-0.2.1.dist-info → drf_to_mkdoc-0.2.3.dist-info}/licenses/LICENSE +0 -0
- {drf_to_mkdoc-0.2.1.dist-info → drf_to_mkdoc-0.2.3.dist-info}/top_level.txt +0 -0
|
@@ -6,7 +6,7 @@ from collections import defaultdict
|
|
|
6
6
|
from typing import Any
|
|
7
7
|
|
|
8
8
|
from django.apps import apps
|
|
9
|
-
from django.
|
|
9
|
+
from django.template.loader import render_to_string
|
|
10
10
|
from rest_framework import serializers
|
|
11
11
|
|
|
12
12
|
from drf_to_mkdoc.conf.settings import drf_to_mkdoc_settings
|
|
@@ -14,16 +14,12 @@ from drf_to_mkdoc.utils.commons.file_utils import write_file
|
|
|
14
14
|
from drf_to_mkdoc.utils.commons.operation_utils import (
|
|
15
15
|
extract_app_from_operation_id,
|
|
16
16
|
extract_viewset_name_from_operation_id,
|
|
17
|
-
format_method_badge,
|
|
18
17
|
)
|
|
19
18
|
from drf_to_mkdoc.utils.commons.path_utils import create_safe_filename
|
|
20
19
|
from drf_to_mkdoc.utils.commons.schema_utils import get_custom_schema
|
|
21
20
|
from drf_to_mkdoc.utils.extractors.query_parameter_extractors import (
|
|
22
21
|
extract_query_parameters_from_view,
|
|
23
22
|
)
|
|
24
|
-
from drf_to_mkdoc.utils.md_generators.query_parameters_generators import (
|
|
25
|
-
generate_query_parameters_md,
|
|
26
|
-
)
|
|
27
23
|
|
|
28
24
|
logger = logging.getLogger()
|
|
29
25
|
|
|
@@ -370,10 +366,17 @@ def _enhance_method_field_schema(_operation_id, schema: dict, _components: dict)
|
|
|
370
366
|
|
|
371
367
|
def _resolve_schema_reference(schema: dict, components: dict) -> dict:
|
|
372
368
|
"""Resolve $ref references in schema."""
|
|
373
|
-
if "$ref" in schema:
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
369
|
+
if "$ref" not in schema:
|
|
370
|
+
return schema
|
|
371
|
+
|
|
372
|
+
ref = schema["$ref"]
|
|
373
|
+
target = components.get("schemas", {}).get(ref.split("/")[-1], {})
|
|
374
|
+
# Work on a copy to avoid mutating components
|
|
375
|
+
resolved = dict(target) if isinstance(target, dict) else {}
|
|
376
|
+
for key, value in schema.items():
|
|
377
|
+
if key != "$ref":
|
|
378
|
+
resolved[key] = value
|
|
379
|
+
return resolved
|
|
377
380
|
|
|
378
381
|
|
|
379
382
|
def _handle_all_of_schema(schema: dict, components: dict, _for_response: bool) -> dict:
|
|
@@ -405,16 +408,22 @@ def _handle_all_of_schema(schema: dict, components: dict, _for_response: bool) -
|
|
|
405
408
|
|
|
406
409
|
def _get_explicit_value(schema: dict):
|
|
407
410
|
"""Get explicit value from schema (enum, example, or default)."""
|
|
408
|
-
# Ensure schema is a dictionary
|
|
409
411
|
if not isinstance(schema, dict):
|
|
410
412
|
return None
|
|
411
413
|
|
|
412
414
|
if "enum" in schema:
|
|
413
415
|
return schema["enum"][0]
|
|
416
|
+
|
|
414
417
|
if "example" in schema:
|
|
415
418
|
return schema["example"]
|
|
419
|
+
|
|
416
420
|
if "default" in schema:
|
|
421
|
+
# For array types with items schema, don't use empty default
|
|
422
|
+
# Let the generator create a proper example instead
|
|
423
|
+
if schema.get("type") == "array" and "items" in schema:
|
|
424
|
+
return None
|
|
417
425
|
return schema["default"]
|
|
426
|
+
|
|
418
427
|
return None
|
|
419
428
|
|
|
420
429
|
|
|
@@ -503,114 +512,206 @@ def format_schema_as_json_example(
|
|
|
503
512
|
if description:
|
|
504
513
|
result += f"{description}\n\n"
|
|
505
514
|
|
|
506
|
-
|
|
507
|
-
result += json.dumps(example_json, indent=2)
|
|
508
|
-
result += "\n```\n"
|
|
515
|
+
return json.dumps(example_json, indent=2)
|
|
509
516
|
|
|
510
|
-
return result
|
|
511
517
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
path: str, method: str, endpoint_data: dict[str, Any], components: dict[str, Any]
|
|
518
|
+
def _format_schema_for_display(
|
|
519
|
+
operation_id: str, schema: dict, components: dict, for_response: bool = True
|
|
515
520
|
) -> str:
|
|
516
|
-
"""
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
521
|
+
"""Format schema as a displayable string with JSON example."""
|
|
522
|
+
if not schema:
|
|
523
|
+
return ""
|
|
524
|
+
|
|
525
|
+
if "$ref" in schema:
|
|
526
|
+
return format_schema_as_json_example(
|
|
527
|
+
operation_id, schema["$ref"], components, for_response
|
|
528
|
+
)
|
|
523
529
|
|
|
524
|
-
|
|
525
|
-
content += _add_path_parameters(parameters)
|
|
526
|
-
content += _add_query_parameters(method, path, operation_id)
|
|
527
|
-
content += _add_request_body(operation_id, request_body, components)
|
|
528
|
-
content += _add_responses(operation_id, responses, components)
|
|
530
|
+
return schema_to_example_json(operation_id, schema, components, for_response)
|
|
529
531
|
|
|
530
|
-
return content
|
|
531
532
|
|
|
533
|
+
def _generate_field_value(
|
|
534
|
+
field_name: str,
|
|
535
|
+
prop_schema: dict,
|
|
536
|
+
operation_id: str,
|
|
537
|
+
components: dict,
|
|
538
|
+
is_response: bool = True,
|
|
539
|
+
) -> Any:
|
|
540
|
+
"""Generate a realistic value for a specific field based on its name and schema."""
|
|
541
|
+
# Get field-specific generator from settings
|
|
542
|
+
field_generator = get_field_generator(field_name)
|
|
532
543
|
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
) -> str:
|
|
536
|
-
"""Create the header section of the endpoint documentation."""
|
|
537
|
-
stylesheets = [
|
|
538
|
-
"stylesheets/endpoints/endpoint-content.css",
|
|
539
|
-
"stylesheets/endpoints/badges.css",
|
|
540
|
-
"stylesheets/endpoints/base.css",
|
|
541
|
-
"stylesheets/endpoints/responsive.css",
|
|
542
|
-
"stylesheets/endpoints/theme-toggle.css",
|
|
543
|
-
"stylesheets/endpoints/layout.css",
|
|
544
|
-
"stylesheets/endpoints/sections.css",
|
|
545
|
-
"stylesheets/endpoints/animations.css",
|
|
546
|
-
"stylesheets/endpoints/accessibility.css",
|
|
547
|
-
"stylesheets/endpoints/loading.css",
|
|
548
|
-
"stylesheets/endpoints/try-out-sidebar.css",
|
|
549
|
-
]
|
|
550
|
-
scripts = [
|
|
551
|
-
"javascripts/try-out-sidebar.js",
|
|
552
|
-
]
|
|
553
|
-
prefix_path = f"{drf_to_mkdoc_settings.PROJECT_NAME}/"
|
|
554
|
-
css_links = "\n".join(
|
|
555
|
-
f'<link rel="stylesheet" href="{static(prefix_path + path)}">' for path in stylesheets
|
|
556
|
-
)
|
|
557
|
-
js_scripts = "\n".join(
|
|
558
|
-
f'<script src="{static(prefix_path + path)}" defer></script>' for path in scripts
|
|
559
|
-
)
|
|
560
|
-
content = f"""
|
|
561
|
-
<!-- inject CSS and JS directly -->
|
|
562
|
-
{css_links}
|
|
563
|
-
{js_scripts}
|
|
564
|
-
"""
|
|
565
|
-
content += f"# {method.upper()} {path}\n\n"
|
|
566
|
-
content += f"{format_method_badge(method)} `{path}`\n\n"
|
|
567
|
-
content += f"**View class:** {extract_viewset_name_from_operation_id(operation_id)}\n\n"
|
|
568
|
-
|
|
569
|
-
if summary:
|
|
570
|
-
content += f"## Overview\n\n{summary}\n\n"
|
|
571
|
-
if operation_id:
|
|
572
|
-
content += f"**Operation ID:** `{operation_id}`\n\n"
|
|
573
|
-
if description:
|
|
574
|
-
content += f"{description}\n\n"
|
|
544
|
+
if field_generator:
|
|
545
|
+
return field_generator(prop_schema)
|
|
575
546
|
|
|
576
|
-
|
|
547
|
+
# Fallback to schema-based generation
|
|
548
|
+
return schema_to_example_json(operation_id, prop_schema, components, is_response)
|
|
577
549
|
|
|
578
550
|
|
|
579
|
-
def
|
|
580
|
-
"""
|
|
581
|
-
|
|
582
|
-
if not path_params:
|
|
583
|
-
return ""
|
|
551
|
+
def get_field_generator(field_name: str):
|
|
552
|
+
"""Get appropriate generator function for a field name from settings."""
|
|
553
|
+
return drf_to_mkdoc_settings.FIELD_GENERATORS.get(field_name.lower())
|
|
584
554
|
|
|
585
|
-
content = "## Path Parameters\n\n"
|
|
586
|
-
content += "| Name | Type | Required | Description |\n"
|
|
587
|
-
content += "|------|------|----------|-------------|\n"
|
|
588
555
|
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
param_type = param.get("schema", {}).get("type", "string")
|
|
592
|
-
required = "Yes" if param.get("required", False) else "No"
|
|
593
|
-
desc = param.get("description", "")
|
|
594
|
-
content += f"| `{name}` | `{param_type}` | {required} | {desc} |\n"
|
|
556
|
+
def _generate_examples(operation_id: str, schema: dict, components: dict) -> list:
|
|
557
|
+
"""Generate examples for a schema."""
|
|
595
558
|
|
|
596
|
-
|
|
597
|
-
|
|
559
|
+
if "$ref" in schema:
|
|
560
|
+
schema = _resolve_schema_reference(schema, components)
|
|
561
|
+
|
|
562
|
+
examples = []
|
|
563
|
+
|
|
564
|
+
# Handle object with array properties
|
|
565
|
+
if schema.get("type") == "object" and "properties" in schema:
|
|
566
|
+
empty_example = {}
|
|
567
|
+
populated_example = {}
|
|
568
|
+
has_array_default = False
|
|
569
|
+
|
|
570
|
+
# Check for array fields with default=[]
|
|
571
|
+
for _prop_name, prop_schema in schema["properties"].items():
|
|
572
|
+
resolved_prop_schema = (
|
|
573
|
+
_resolve_schema_reference(prop_schema, components)
|
|
574
|
+
if "$ref" in prop_schema
|
|
575
|
+
else prop_schema
|
|
576
|
+
)
|
|
577
|
+
if (
|
|
578
|
+
resolved_prop_schema.get("type") == "array"
|
|
579
|
+
and resolved_prop_schema.get("default") == []
|
|
580
|
+
):
|
|
581
|
+
has_array_default = True
|
|
582
|
+
break
|
|
583
|
+
|
|
584
|
+
# Generate examples
|
|
585
|
+
for prop_name, prop_schema in schema["properties"].items():
|
|
586
|
+
resolved_prop_schema = (
|
|
587
|
+
_resolve_schema_reference(prop_schema, components)
|
|
588
|
+
if "$ref" in prop_schema
|
|
589
|
+
else prop_schema
|
|
590
|
+
)
|
|
598
591
|
|
|
592
|
+
if (
|
|
593
|
+
resolved_prop_schema.get("type") == "array"
|
|
594
|
+
and resolved_prop_schema.get("default") == []
|
|
595
|
+
):
|
|
596
|
+
empty_example[prop_name] = []
|
|
597
|
+
items_schema = resolved_prop_schema.get("items", {})
|
|
598
|
+
populated_example[prop_name] = [
|
|
599
|
+
_generate_field_value(
|
|
600
|
+
prop_name, items_schema, operation_id, components, True
|
|
601
|
+
)
|
|
602
|
+
]
|
|
603
|
+
else:
|
|
604
|
+
value = _generate_field_value(
|
|
605
|
+
prop_name, resolved_prop_schema, operation_id, components, True
|
|
606
|
+
)
|
|
607
|
+
empty_example[prop_name] = value
|
|
608
|
+
populated_example[prop_name] = value
|
|
599
609
|
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
610
|
+
if has_array_default:
|
|
611
|
+
examples.append(empty_example)
|
|
612
|
+
examples.append(populated_example)
|
|
613
|
+
else:
|
|
614
|
+
examples.append(empty_example)
|
|
615
|
+
|
|
616
|
+
# Handle array field with default=[]
|
|
617
|
+
elif schema.get("type") == "array" and schema.get("default") == []:
|
|
618
|
+
examples.append([])
|
|
619
|
+
items_schema = schema.get("items", {})
|
|
620
|
+
populated_example = [
|
|
621
|
+
_generate_field_value("items", items_schema, operation_id, components, True)
|
|
622
|
+
]
|
|
623
|
+
examples.append(populated_example)
|
|
624
|
+
else:
|
|
625
|
+
example = _generate_field_value("root", schema, operation_id, components, True)
|
|
626
|
+
examples.append(example)
|
|
627
|
+
|
|
628
|
+
return examples
|
|
605
629
|
|
|
606
|
-
query_params = extract_query_parameters_from_view(operation_id)
|
|
607
|
-
_add_custom_parameters(operation_id, query_params)
|
|
608
630
|
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
return "## Query Parameters\n\n" + query_params_content
|
|
631
|
+
def _prepare_response_data(operation_id: str, responses: dict, components: dict) -> list:
|
|
632
|
+
"""Prepare response data for template rendering."""
|
|
612
633
|
|
|
613
|
-
|
|
634
|
+
formatted_responses = []
|
|
635
|
+
for status_code, response_data in responses.items():
|
|
636
|
+
schema = response_data.get("content", {}).get("application/json", {}).get("schema", {})
|
|
637
|
+
|
|
638
|
+
examples = _generate_examples(operation_id, schema, components)
|
|
639
|
+
|
|
640
|
+
formatted_response = {
|
|
641
|
+
"status_code": status_code,
|
|
642
|
+
"description": response_data.get("description", ""),
|
|
643
|
+
"examples": examples,
|
|
644
|
+
}
|
|
645
|
+
formatted_responses.append(formatted_response)
|
|
646
|
+
return formatted_responses
|
|
647
|
+
|
|
648
|
+
|
|
649
|
+
def create_endpoint_page(
|
|
650
|
+
path: str, method: str, endpoint_data: dict[str, Any], components: dict[str, Any]
|
|
651
|
+
) -> str:
|
|
652
|
+
"""Create a documentation page for a single API endpoint."""
|
|
653
|
+
operation_id = endpoint_data.get("operationId", "")
|
|
654
|
+
request_schema = (
|
|
655
|
+
endpoint_data.get("requestBody", {})
|
|
656
|
+
.get("content", {})
|
|
657
|
+
.get("application/json", {})
|
|
658
|
+
.get("schema")
|
|
659
|
+
)
|
|
660
|
+
|
|
661
|
+
# Prepare template context
|
|
662
|
+
context = {
|
|
663
|
+
"path": path,
|
|
664
|
+
"method": method,
|
|
665
|
+
"operation_id": operation_id,
|
|
666
|
+
"summary": endpoint_data.get("summary", ""),
|
|
667
|
+
"description": endpoint_data.get("description", ""),
|
|
668
|
+
"viewset_name": extract_viewset_name_from_operation_id(operation_id),
|
|
669
|
+
"path_params": [
|
|
670
|
+
p for p in endpoint_data.get("parameters", []) if p.get("in") == "path"
|
|
671
|
+
],
|
|
672
|
+
"request_body": endpoint_data.get("requestBody", {}),
|
|
673
|
+
"request_example": _format_schema_for_display(
|
|
674
|
+
operation_id, request_schema, components, False
|
|
675
|
+
)
|
|
676
|
+
if request_schema
|
|
677
|
+
else "",
|
|
678
|
+
"responses": _prepare_response_data(
|
|
679
|
+
operation_id, endpoint_data.get("responses", {}), components
|
|
680
|
+
),
|
|
681
|
+
"stylesheets": [
|
|
682
|
+
"stylesheets/endpoints/endpoint-content.css",
|
|
683
|
+
"stylesheets/endpoints/badges.css",
|
|
684
|
+
"stylesheets/endpoints/base.css",
|
|
685
|
+
"stylesheets/endpoints/responsive.css",
|
|
686
|
+
"stylesheets/endpoints/theme-toggle.css",
|
|
687
|
+
"stylesheets/endpoints/layout.css",
|
|
688
|
+
"stylesheets/endpoints/sections.css",
|
|
689
|
+
"stylesheets/endpoints/animations.css",
|
|
690
|
+
"stylesheets/endpoints/accessibility.css",
|
|
691
|
+
"stylesheets/endpoints/loading.css",
|
|
692
|
+
"stylesheets/try-out/main.css",
|
|
693
|
+
],
|
|
694
|
+
"scripts": [
|
|
695
|
+
"javascripts/try-out/modal.js",
|
|
696
|
+
"javascripts/try-out/tabs.js",
|
|
697
|
+
"javascripts/try-out/form-manager.js",
|
|
698
|
+
"javascripts/try-out/request-executor.js",
|
|
699
|
+
"javascripts/try-out/suggestions.js",
|
|
700
|
+
"javascripts/try-out/main.js",
|
|
701
|
+
],
|
|
702
|
+
"prefix_path": f"{drf_to_mkdoc_settings.PROJECT_NAME}/",
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
# Add query parameters if it's a list endpoint
|
|
706
|
+
if _is_list_endpoint(method, path, operation_id):
|
|
707
|
+
query_params = extract_query_parameters_from_view(operation_id)
|
|
708
|
+
_add_custom_parameters(operation_id, query_params)
|
|
709
|
+
for key, value in query_params.items():
|
|
710
|
+
# Prevent duplicates while preserving order
|
|
711
|
+
query_params[key] = list(dict.fromkeys(value))
|
|
712
|
+
context["query_parameters"] = query_params
|
|
713
|
+
|
|
714
|
+
return render_to_string("endpoints/detail/base.html", context)
|
|
614
715
|
|
|
615
716
|
|
|
616
717
|
def _is_list_endpoint(method: str, path: str, operation_id: str) -> bool:
|
|
@@ -632,77 +733,6 @@ def _add_custom_parameters(operation_id: str, query_params: dict) -> None:
|
|
|
632
733
|
query_params[queryparam_type].append(parameter["name"])
|
|
633
734
|
|
|
634
735
|
|
|
635
|
-
def _add_request_body(operation_id: str, request_body: dict, components: dict[str, Any]) -> str:
|
|
636
|
-
"""Add request body section to the documentation."""
|
|
637
|
-
if not request_body:
|
|
638
|
-
return ""
|
|
639
|
-
|
|
640
|
-
content = "## Request Body\n\n"
|
|
641
|
-
req_schema = request_body.get("content", {}).get("application/json", {}).get("schema")
|
|
642
|
-
|
|
643
|
-
if req_schema and "$ref" in req_schema:
|
|
644
|
-
content += (
|
|
645
|
-
format_schema_as_json_example(
|
|
646
|
-
operation_id, req_schema["$ref"], components, for_response=False
|
|
647
|
-
)
|
|
648
|
-
+ "\n"
|
|
649
|
-
)
|
|
650
|
-
|
|
651
|
-
return content
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
def _add_responses(operation_id: str, responses: dict, components: dict[str, Any]) -> str:
|
|
655
|
-
"""Add responses section to the documentation."""
|
|
656
|
-
if not responses:
|
|
657
|
-
return ""
|
|
658
|
-
|
|
659
|
-
content = "## Responses\n\n"
|
|
660
|
-
for status_code, response_data in responses.items():
|
|
661
|
-
content += _format_single_response(operation_id, status_code, response_data, components)
|
|
662
|
-
|
|
663
|
-
return content
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
def _format_single_response(
|
|
667
|
-
operation_id: str, status_code: str, response_data: dict, components: dict[str, Any]
|
|
668
|
-
) -> str:
|
|
669
|
-
"""Format a single response entry."""
|
|
670
|
-
content = f"### {status_code}\n\n"
|
|
671
|
-
|
|
672
|
-
if desc := response_data.get("description", ""):
|
|
673
|
-
content += f"{desc}\n\n"
|
|
674
|
-
|
|
675
|
-
resp_schema = response_data.get("content", {}).get("application/json", {}).get("schema", {})
|
|
676
|
-
|
|
677
|
-
content += _format_response_schema(operation_id, resp_schema, components)
|
|
678
|
-
return content
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
def _format_response_schema(
|
|
682
|
-
operation_id: str, resp_schema: dict, components: dict[str, Any]
|
|
683
|
-
) -> str:
|
|
684
|
-
"""Format the response schema as JSON example."""
|
|
685
|
-
if "$ref" in resp_schema:
|
|
686
|
-
return (
|
|
687
|
-
format_schema_as_json_example(
|
|
688
|
-
operation_id, resp_schema["$ref"], components, for_response=True
|
|
689
|
-
)
|
|
690
|
-
+ "\n"
|
|
691
|
-
)
|
|
692
|
-
if resp_schema.get("type") == "array" and "$ref" in resp_schema.get("items", {}):
|
|
693
|
-
item_ref = resp_schema["items"]["$ref"]
|
|
694
|
-
return (
|
|
695
|
-
format_schema_as_json_example(operation_id, item_ref, components, for_response=True)
|
|
696
|
-
+ "\n"
|
|
697
|
-
)
|
|
698
|
-
content = "```json\n"
|
|
699
|
-
content += json.dumps(
|
|
700
|
-
schema_to_example_json(operation_id, resp_schema, components), indent=2
|
|
701
|
-
)
|
|
702
|
-
content += "\n```\n"
|
|
703
|
-
return content
|
|
704
|
-
|
|
705
|
-
|
|
706
736
|
def parse_endpoints_from_schema(paths: dict[str, Any]) -> dict[str, list[dict[str, Any]]]:
|
|
707
737
|
"""Parse endpoints from OpenAPI schema and organize by app"""
|
|
708
738
|
|