@@ -1800,7 +1800,9 @@ def get_openapi_schema(
1800
1800
1801
1801
# Build final components and paths
1802
1802
components = self ._build_openapi_components (definitions , config ["security_schemes" ])
1803
- output .update (self ._finalize_openapi_output (components , config ["tags" ], paths , config ["external_documentation" ]))
1803
+ output .update (
1804
+ self ._finalize_openapi_output (components , config ["tags" ], paths , config ["external_documentation" ]),
1805
+ )
1804
1806
1805
1807
# Apply schema fixes and return result
1806
1808
return self ._apply_schema_fixes (output )
@@ -1810,8 +1812,8 @@ def _resolve_openapi_config(self, **kwargs) -> dict[str, Any]:
1810
1812
# DEPRECATION: Will be removed in v4.0.0. Use configure_api() instead.
1811
1813
# Maintained for backwards compatibility.
1812
1814
# See: https://github.com/aws-powertools/powertools-lambda-python/issues/6122
1813
- resolved = {}
1814
-
1815
+ resolved : dict [ str , Any ] = {}
1816
+
1815
1817
# Handle fields with specific default value checks
1816
1818
self ._resolve_title_config (resolved , kwargs )
1817
1819
self ._resolve_version_config (resolved , kwargs )
@@ -1823,41 +1825,112 @@ def _resolve_openapi_config(self, **kwargs) -> dict[str, Any]:
1823
1825
return resolved
1824
1826
1825
1827
def _resolve_title_config (self , resolved : dict [str , Any ], kwargs : dict [str , Any ]) -> None :
1826
- """Resolve title configuration with fallback to openapi_config."""
1828
+ """
1829
+ Resolve title configuration with fallback to openapi_config.
1830
+
1831
+ Checks if the provided title is the default value, and if so, uses the
1832
+ title from openapi_config if available. This allows users to configure
1833
+ a default title through the OpenAPI configuration object.
1834
+
1835
+ Parameters
1836
+ ----------
1837
+ resolved : dict[str, Any]
1838
+ Dictionary to store the resolved configuration (modified in place)
1839
+ kwargs : dict[str, Any]
1840
+ Keyword arguments passed to get_openapi_schema
1841
+ """
1827
1842
resolved ["title" ] = kwargs ["title" ]
1828
1843
if kwargs ["title" ] == DEFAULT_OPENAPI_TITLE and self .openapi_config .title :
1829
1844
resolved ["title" ] = self .openapi_config .title
1830
1845
1831
1846
def _resolve_version_config (self , resolved : dict [str , Any ], kwargs : dict [str , Any ]) -> None :
1832
- """Resolve version configuration with fallback to openapi_config."""
1847
+ """
1848
+ Resolve version configuration with fallback to openapi_config.
1849
+
1850
+ Checks if the provided version is the default value, and if so, uses the
1851
+ version from openapi_config if available. This allows users to configure
1852
+ a default API version through the OpenAPI configuration object.
1853
+
1854
+ Parameters
1855
+ ----------
1856
+ resolved : dict[str, Any]
1857
+ Dictionary to store the resolved configuration (modified in place)
1858
+ kwargs : dict[str, Any]
1859
+ Keyword arguments passed to get_openapi_schema
1860
+ """
1833
1861
resolved ["version" ] = kwargs ["version" ]
1834
1862
if kwargs ["version" ] == DEFAULT_API_VERSION and self .openapi_config .version :
1835
1863
resolved ["version" ] = self .openapi_config .version
1836
1864
1837
1865
def _resolve_openapi_version_config (self , resolved : dict [str , Any ], kwargs : dict [str , Any ]) -> None :
1838
- """Resolve openapi_version configuration with fallback to openapi_config."""
1866
+ """
1867
+ Resolve openapi_version configuration with fallback to openapi_config.
1868
+
1869
+ Checks if the provided OpenAPI version is the default value, and if so, uses
1870
+ the version from openapi_config if available. This allows users to configure
1871
+ a specific OpenAPI version through the OpenAPI configuration object.
1872
+
1873
+ Parameters
1874
+ ----------
1875
+ resolved : dict[str, Any]
1876
+ Dictionary to store the resolved configuration (modified in place)
1877
+ kwargs : dict[str, Any]
1878
+ Keyword arguments passed to get_openapi_schema
1879
+ """
1839
1880
resolved ["openapi_version" ] = kwargs ["openapi_version" ]
1840
1881
if kwargs ["openapi_version" ] == DEFAULT_OPENAPI_VERSION and self .openapi_config .openapi_version :
1841
1882
resolved ["openapi_version" ] = self .openapi_config .openapi_version
1842
1883
1843
1884
def _resolve_remaining_config_fields (self , resolved : dict [str , Any ], kwargs : dict [str , Any ]) -> None :
1844
- """Resolve remaining configuration fields with simple fallbacks."""
1845
- resolved .update ({
1846
- "summary" : kwargs ["summary" ] or self .openapi_config .summary ,
1847
- "description" : kwargs ["description" ] or self .openapi_config .description ,
1848
- "tags" : kwargs ["tags" ] or self .openapi_config .tags ,
1849
- "servers" : kwargs ["servers" ] or self .openapi_config .servers ,
1850
- "terms_of_service" : kwargs ["terms_of_service" ] or self .openapi_config .terms_of_service ,
1851
- "contact" : kwargs ["contact" ] or self .openapi_config .contact ,
1852
- "license_info" : kwargs ["license_info" ] or self .openapi_config .license_info ,
1853
- "security_schemes" : kwargs ["security_schemes" ] or self .openapi_config .security_schemes ,
1854
- "security" : kwargs ["security" ] or self .openapi_config .security ,
1855
- "external_documentation" : kwargs ["external_documentation" ] or self .openapi_config .external_documentation ,
1856
- "openapi_extensions" : kwargs ["openapi_extensions" ] or self .openapi_config .openapi_extensions ,
1857
- })
1885
+ """
1886
+ Resolve remaining configuration fields with simple fallbacks.
1887
+
1888
+ For fields that use simple OR logic, use the provided value from kwargs
1889
+ or fall back to the value from openapi_config. This includes fields like
1890
+ summary, description, tags, servers, etc.
1891
+
1892
+ Parameters
1893
+ ----------
1894
+ resolved : dict[str, Any]
1895
+ Dictionary to store the resolved configuration (modified in place)
1896
+ kwargs : dict[str, Any]
1897
+ Keyword arguments passed to get_openapi_schema
1898
+ """
1899
+ resolved .update (
1900
+ {
1901
+ "summary" : kwargs ["summary" ] or self .openapi_config .summary ,
1902
+ "description" : kwargs ["description" ] or self .openapi_config .description ,
1903
+ "tags" : kwargs ["tags" ] or self .openapi_config .tags ,
1904
+ "servers" : kwargs ["servers" ] or self .openapi_config .servers ,
1905
+ "terms_of_service" : kwargs ["terms_of_service" ] or self .openapi_config .terms_of_service ,
1906
+ "contact" : kwargs ["contact" ] or self .openapi_config .contact ,
1907
+ "license_info" : kwargs ["license_info" ] or self .openapi_config .license_info ,
1908
+ "security_schemes" : kwargs ["security_schemes" ] or self .openapi_config .security_schemes ,
1909
+ "security" : kwargs ["security" ] or self .openapi_config .security ,
1910
+ "external_documentation" : kwargs ["external_documentation" ]
1911
+ or self .openapi_config .external_documentation ,
1912
+ "openapi_extensions" : kwargs ["openapi_extensions" ] or self .openapi_config .openapi_extensions ,
1913
+ },
1914
+ )
1858
1915
1859
1916
def _build_base_openapi_structure (self , config : dict [str , Any ]) -> dict [str , Any ]:
1860
- """Build the base OpenAPI structure with info, servers, and security."""
1917
+ """
1918
+ Build the base OpenAPI structure with info, servers, and security.
1919
+
1920
+ Creates the foundation of an OpenAPI schema including the required fields
1921
+ (openapi version, info) and optional fields (servers, security) based on
1922
+ the resolved configuration.
1923
+
1924
+ Parameters
1925
+ ----------
1926
+ config : dict[str, Any]
1927
+ Resolved OpenAPI configuration dictionary containing title, version, etc.
1928
+
1929
+ Returns
1930
+ -------
1931
+ dict[str, Any]
1932
+ Base OpenAPI structure dictionary ready for paths and components
1933
+ """
1861
1934
openapi_version = self ._determine_openapi_version (config ["openapi_version" ])
1862
1935
1863
1936
# Start with the bare minimum required for a valid OpenAPI schema
@@ -1885,9 +1958,13 @@ def _build_base_openapi_structure(self, config: dict[str, Any]) -> dict[str, Any
1885
1958
** openapi_extensions ,
1886
1959
}
1887
1960
1888
- def _process_routes_for_openapi (self , security_schemes : dict [str , SecurityScheme ] | None ) -> tuple [dict [str , dict [str , Any ]], dict [str , dict [str , Any ]]]:
1961
+ def _process_routes_for_openapi (
1962
+ self ,
1963
+ security_schemes : dict [str , SecurityScheme ] | None ,
1964
+ ) -> tuple [dict [str , dict [str , Any ]], dict [str , dict [str , Any ]]]:
1889
1965
"""Process all routes and build paths and definitions."""
1890
1966
from pydantic .json_schema import GenerateJsonSchema
1967
+
1891
1968
from aws_lambda_powertools .event_handler .openapi .compat import (
1892
1969
get_compat_model_name_map ,
1893
1970
get_definitions ,
@@ -1912,7 +1989,7 @@ def _process_routes_for_openapi(self, security_schemes: dict[str, SecurityScheme
1912
1989
# Add routes to the OpenAPI schema
1913
1990
for route in all_routes :
1914
1991
self ._validate_route_security (route , security_schemes )
1915
-
1992
+
1916
1993
if not route .include_in_schema :
1917
1994
continue
1918
1995
@@ -1943,45 +2020,71 @@ def _validate_route_security(self, route, security_schemes: dict[str, SecuritySc
1943
2020
"See: https://docs.powertools.aws.dev/lambda/python/latest/core/event_handler/api_gateway/#security-schemes" ,
1944
2021
)
1945
2022
1946
- def _build_openapi_components (self , definitions : dict [str , dict [str , Any ]], security_schemes : dict [str , SecurityScheme ] | None ) -> dict [str , dict [str , Any ]]:
2023
+ def _build_openapi_components (
2024
+ self ,
2025
+ definitions : dict [str , dict [str , Any ]],
2026
+ security_schemes : dict [str , SecurityScheme ] | None ,
2027
+ ) -> dict [str , dict [str , Any ]]:
1947
2028
"""Build the components section of the OpenAPI schema."""
1948
2029
components : dict [str , dict [str , Any ]] = {}
1949
-
2030
+
1950
2031
if definitions :
1951
2032
components ["schemas" ] = self ._generate_schemas (definitions )
1952
2033
if security_schemes :
1953
2034
components ["securitySchemes" ] = security_schemes
1954
-
2035
+
1955
2036
return components
1956
2037
1957
- def _finalize_openapi_output (self , components : dict [str , dict [str , Any ]], tags , paths : dict [str , dict [str , Any ]], external_documentation ) -> dict [str , Any ]:
2038
+ def _finalize_openapi_output (
2039
+ self ,
2040
+ components : dict [str , dict [str , Any ]],
2041
+ tags ,
2042
+ paths : dict [str , dict [str , Any ]],
2043
+ external_documentation ,
2044
+ ) -> dict [str , Any ]:
1958
2045
"""Finalize the OpenAPI output with components, tags, and paths."""
1959
2046
from aws_lambda_powertools .event_handler .openapi .models import PathItem , Tag
1960
2047
1961
- output = {}
1962
-
2048
+ output : dict [ str , Any ] = {}
2049
+
1963
2050
if components :
1964
2051
output ["components" ] = components
1965
2052
if tags :
1966
2053
output ["tags" ] = [Tag (name = tag ) if isinstance (tag , str ) else tag for tag in tags ]
1967
2054
if external_documentation :
1968
2055
output ["externalDocs" ] = external_documentation
1969
2056
1970
- output ["paths" ] = {k : PathItem (** v ) for k , v in paths .items ()}
1971
-
2057
+ output ["paths" ] = {k : PathItem (** v ) if not isinstance ( v , PathItem ) else v for k , v in paths .items ()}
2058
+
1972
2059
return output
1973
2060
1974
2061
def _apply_schema_fixes (self , output : dict [str , Any ]) -> OpenAPI :
1975
- """Apply schema fixes and return the final OpenAPI model."""
2062
+ """
2063
+ Apply schema fixes and return the final OpenAPI model.
2064
+
2065
+ This method handles various schema fixes, including resolving missing
2066
+ component references for UploadFile parameters that can cause validation
2067
+ errors in OpenAPI tools like Swagger Editor.
2068
+
2069
+ Parameters
2070
+ ----------
2071
+ output : dict[str, Any]
2072
+ The OpenAPI schema dictionary to process
2073
+
2074
+ Returns
2075
+ -------
2076
+ OpenAPI
2077
+ The final OpenAPI model with all fixes applied
2078
+ """
1976
2079
from aws_lambda_powertools .event_handler .openapi .models import OpenAPI
1977
- from aws_lambda_powertools .event_handler .openapi .upload_file_fix import fix_upload_file_schema
2080
+ from aws_lambda_powertools .event_handler .openapi .params import fix_upload_file_schema_references
1978
2081
1979
2082
# First create the OpenAPI model
1980
2083
result = OpenAPI (** output )
1981
2084
1982
- # Convert the model to a dict and apply the fix
2085
+ # Convert the model to a dict and apply the upload file schema fix
1983
2086
result_dict = result .model_dump (by_alias = True )
1984
- fixed_dict = fix_upload_file_schema (result_dict )
2087
+ fixed_dict = fix_upload_file_schema_references (result_dict )
1985
2088
1986
2089
# Reconstruct the model with the fixed dict
1987
2090
return OpenAPI (** fixed_dict )
0 commit comments