From 0773bcced5bb00a90efcb1fa40504a693908c6ba Mon Sep 17 00:00:00 2001 From: Leandro Damascena Date: Mon, 3 Mar 2025 16:51:40 +0000 Subject: [PATCH 1/4] Adding specific method for OpenAPI configuration --- Makefile | 2 +- .../event_handler/api_gateway.py | 114 +++++++++++++++++- .../event_handler/openapi/config.py | 76 ++++++++++++ .../_pydantic/test_openapi_config.py | 87 +++++++++++++ .../_pydantic/test_openapi_params.py | 2 +- 5 files changed, 277 insertions(+), 4 deletions(-) create mode 100644 aws_lambda_powertools/event_handler/openapi/config.py create mode 100644 tests/functional/event_handler/_pydantic/test_openapi_config.py diff --git a/Makefile b/Makefile index 4bb1e78390c..65df3162f0e 100644 --- a/Makefile +++ b/Makefile @@ -84,7 +84,7 @@ complexity-baseline: $(info Maintenability index) poetry run radon mi aws_lambda_powertools $(info Cyclomatic complexity index) - poetry run xenon --max-absolute C --max-modules A --max-average A aws_lambda_powertools --exclude aws_lambda_powertools/shared/json_encoder.py,aws_lambda_powertools/utilities/validation/base.py + poetry run xenon --max-absolute C --max-modules A --max-average A aws_lambda_powertools --exclude aws_lambda_powertools/shared/json_encoder.py,aws_lambda_powertools/utilities/validation/base.py,aws_lambda_powertools/event_handler/api_gateway.py # # Use `poetry version /` for version bump diff --git a/aws_lambda_powertools/event_handler/api_gateway.py b/aws_lambda_powertools/event_handler/api_gateway.py index 5eba4220c22..c553ca453e0 100644 --- a/aws_lambda_powertools/event_handler/api_gateway.py +++ b/aws_lambda_powertools/event_handler/api_gateway.py @@ -18,6 +18,7 @@ from aws_lambda_powertools.event_handler import content_types from aws_lambda_powertools.event_handler.exceptions import NotFoundError, ServiceError +from aws_lambda_powertools.event_handler.openapi.config import OpenAPIConfig from aws_lambda_powertools.event_handler.openapi.constants import DEFAULT_API_VERSION, DEFAULT_OPENAPI_VERSION from aws_lambda_powertools.event_handler.openapi.exceptions import RequestValidationError, SchemaValidationError from aws_lambda_powertools.event_handler.openapi.types import ( @@ -1530,6 +1531,7 @@ def __init__( self.context: dict = {} # early init as customers might add context before event resolution self.processed_stack_frames = [] self._response_builder_class = ResponseBuilder[BaseProxyEvent] + self.openapi_config = OpenAPIConfig() # starting an empty dataclass # Allow for a custom serializer or a concise json serialization self._serializer = serializer or partial(json.dumps, separators=(",", ":"), cls=Encoder) @@ -1544,7 +1546,7 @@ def __init__( def get_openapi_schema( self, *, - title: str = "Powertools API", + title: str = "Powertools for AWS Lambda (Python) API", version: str = DEFAULT_API_VERSION, openapi_version: str = DEFAULT_OPENAPI_VERSION, summary: str | None = None, @@ -1596,6 +1598,29 @@ def get_openapi_schema( The OpenAPI schema as a pydantic model. """ + # DEPRECATION: Will be removed in v4.0.0. Use configure_api() instead. + # Maintained for backwards compatibility. + # See: https://github.com/aws-powertools/powertools-lambda-python/issues/6122 + if title == "Powertools for AWS Lambda (Python) API" and self.openapi_config.title: + title = self.openapi_config.title + + if version == DEFAULT_API_VERSION and self.openapi_config.version: + version = self.openapi_config.version + + if openapi_version == DEFAULT_OPENAPI_VERSION and self.openapi_config.openapi_version: + openapi_version = self.openapi_config.openapi_version + + summary = summary or self.openapi_config.summary + description = description or self.openapi_config.description + tags = tags or self.openapi_config.tags + servers = servers or self.openapi_config.servers + terms_of_service = terms_of_service or self.openapi_config.terms_of_service + contact = contact or self.openapi_config.contact + license_info = license_info or self.openapi_config.license_info + security_schemes = security_schemes or self.openapi_config.security_schemes + security = security or self.openapi_config.security + openapi_extensions = openapi_extensions or self.openapi_config.openapi_extensions + from aws_lambda_powertools.event_handler.openapi.compat import ( GenerateJsonSchema, get_compat_model_name_map, @@ -1726,7 +1751,7 @@ def _determine_openapi_version(openapi_version: str): def get_openapi_json_schema( self, *, - title: str = "Powertools API", + title: str = "Powertools for AWS Lambda (Python) API", version: str = DEFAULT_API_VERSION, openapi_version: str = DEFAULT_OPENAPI_VERSION, summary: str | None = None, @@ -1777,6 +1802,7 @@ def get_openapi_json_schema( str The OpenAPI schema as a JSON serializable dict. """ + from aws_lambda_powertools.event_handler.openapi.compat import model_json return model_json( @@ -1800,6 +1826,89 @@ def get_openapi_json_schema( indent=2, ) + def configure_openapi( + self, + title: str = "Powertools for AWS Lambda (Python) API", + version: str = DEFAULT_API_VERSION, + openapi_version: str = DEFAULT_OPENAPI_VERSION, + summary: str | None = None, + description: str | None = None, + tags: list[Tag | str] | None = None, + servers: list[Server] | None = None, + terms_of_service: str | None = None, + contact: Contact | None = None, + license_info: License | None = None, + security_schemes: dict[str, SecurityScheme] | None = None, + security: list[dict[str, list[str]]] | None = None, + openapi_extensions: dict[str, Any] | None = None, + ): + """Configure OpenAPI specification settings for the API. + + Sets up the OpenAPI documentation configuration that can be later used + when enabling Swagger UI or generating OpenAPI specifications. + + Parameters + ---------- + title: str + The title of the application. + version: str + The version of the OpenAPI document (which is distinct from the OpenAPI Specification version or the API + openapi_version: str, default = "3.0.0" + The version of the OpenAPI Specification (which the document uses). + summary: str, optional + A short summary of what the application does. + description: str, optional + A verbose explanation of the application behavior. + tags: list[Tag, str], optional + A list of tags used by the specification with additional metadata. + servers: list[Server], optional + An array of Server Objects, which provide connectivity information to a target server. + terms_of_service: str, optional + A URL to the Terms of Service for the API. MUST be in the format of a URL. + contact: Contact, optional + The contact information for the exposed API. + license_info: License, optional + The license information for the exposed API. + security_schemes: dict[str, SecurityScheme]], optional + A declaration of the security schemes available to be used in the specification. + security: list[dict[str, list[str]]], optional + A declaration of which security mechanisms are applied globally across the API. + openapi_extensions: Dict[str, Any], optional + Additional OpenAPI extensions as a dictionary. + + Example + -------- + >>> api.configure_openapi( + ... title="My API", + ... version="1.0.0", + ... description="API for managing resources", + ... contact=Contact( + ... name="API Support", + ... email="support@example.com" + ... ) + ... ) + + See Also + -------- + enable_swagger : Method to enable Swagger UI using these configurations + OpenAPIConfig : Data class containing all OpenAPI configuration options + """ + self.openapi_config = OpenAPIConfig( + title=title, + version=version, + openapi_version=openapi_version, + summary=summary, + description=description, + tags=tags, + servers=servers, + terms_of_service=terms_of_service, + contact=contact, + license_info=license_info, + security_schemes=security_schemes, + security=security, + openapi_extensions=openapi_extensions, + ) + def enable_swagger( self, *, @@ -1867,6 +1976,7 @@ def enable_swagger( openapi_extensions: dict[str, Any], optional Additional OpenAPI extensions as a dictionary. """ + from aws_lambda_powertools.event_handler.openapi.compat import model_json from aws_lambda_powertools.event_handler.openapi.models import Server from aws_lambda_powertools.event_handler.openapi.swagger_ui import ( diff --git a/aws_lambda_powertools/event_handler/openapi/config.py b/aws_lambda_powertools/event_handler/openapi/config.py new file mode 100644 index 00000000000..bae3804b39a --- /dev/null +++ b/aws_lambda_powertools/event_handler/openapi/config.py @@ -0,0 +1,76 @@ +from __future__ import annotations + +from dataclasses import dataclass +from typing import TYPE_CHECKING, Any + +from aws_lambda_powertools.event_handler.openapi.constants import DEFAULT_API_VERSION, DEFAULT_OPENAPI_VERSION + +if TYPE_CHECKING: + from aws_lambda_powertools.event_handler.openapi.models import ( + Contact, + License, + SecurityScheme, + Server, + Tag, + ) + + +@dataclass +class OpenAPIConfig: + """Configuration class for OpenAPI specification. + + This class holds all the necessary configuration parameters to generate an OpenAPI specification. + + Parameters + ---------- + title: str + The title of the application. + version: str + The version of the OpenAPI document (which is distinct from the OpenAPI Specification version or the API + openapi_version: str, default = "3.0.0" + The version of the OpenAPI Specification (which the document uses). + summary: str, optional + A short summary of what the application does. + description: str, optional + A verbose explanation of the application behavior. + tags: list[Tag, str], optional + A list of tags used by the specification with additional metadata. + servers: list[Server], optional + An array of Server Objects, which provide connectivity information to a target server. + terms_of_service: str, optional + A URL to the Terms of Service for the API. MUST be in the format of a URL. + contact: Contact, optional + The contact information for the exposed API. + license_info: License, optional + The license information for the exposed API. + security_schemes: dict[str, SecurityScheme]], optional + A declaration of the security schemes available to be used in the specification. + security: list[dict[str, list[str]]], optional + A declaration of which security mechanisms are applied globally across the API. + openapi_extensions: Dict[str, Any], optional + Additional OpenAPI extensions as a dictionary. + + Example + -------- + >>> config = OpenAPIConfig( + ... title="My API", + ... version="1.0.0", + ... description="This is my API description", + ... contact=Contact(name="API Support", email="support@example.com"), + ... servers=[Server(url="https://api.example.com/v1")] + ... ) + """ + + title: str = "Powertools for AWS Lambda (Python) API" + version: str = DEFAULT_API_VERSION + openapi_version: str = DEFAULT_OPENAPI_VERSION + summary: str | None = None + description: str | None = None + tags: list[Tag | str] | None = None + servers: list[Server] | None = None + terms_of_service: str | None = None + contact: Contact | None = None + license_info: License | None = None + security_schemes: dict[str, SecurityScheme] | None = None + security: list[dict[str, list[str]]] | None = None + openapi_extensions: dict[str, Any] | None = None diff --git a/tests/functional/event_handler/_pydantic/test_openapi_config.py b/tests/functional/event_handler/_pydantic/test_openapi_config.py new file mode 100644 index 00000000000..9fc2dd1ce7b --- /dev/null +++ b/tests/functional/event_handler/_pydantic/test_openapi_config.py @@ -0,0 +1,87 @@ +import json + +from aws_lambda_powertools.event_handler import APIGatewayRestResolver + + +def test_export_openapi_schema_with_custom_configuration(): + # GIVEN an API Gateway resolver with OpenAPI validation enabled + app = APIGatewayRestResolver(enable_validation=True) + + # GIVEN custom OpenAPI configuration + openapi_title = "My API" + openapi_myapi_version = "1.1.1-alpha" + app.configure_openapi(title=openapi_title, version=openapi_myapi_version) + + # WHEN we have a simple handler + @app.get("/") + def handler(): + pass + + # WHEN we get the schema + schema = app.get_openapi_schema() + + # THEN the schema should contain our custom configuration + assert schema.info.title == openapi_title + assert schema.info.version == openapi_myapi_version + + +def test_prioritize_direct_parameters_over_stored_configuration(): + + # GIVEN + stored_config = { + "title": "Stored API Title", + "version": "1.0.0", + } + + direct_params = { + "title": "Direct API Title", + "version": "2.0.0", + } + + # GIVEN an API Gateway resolver with OpenAPI validation enabled + app = APIGatewayRestResolver(enable_validation=True) + + app.configure_openapi(**stored_config) + + # WHEN we have a simple handler + @app.get("/") + def handler(): + pass + + # WHEN we get the schema with direct params + schema = app.get_openapi_schema(**direct_params) + + # THEN direct parameters must override stored configuration + assert schema.info.title == direct_params["title"] + assert schema.info.version == direct_params["version"] + + +def test_export_openapi_schema_with_custom_configuration_and_json_export(): + # GIVEN an API Gateway resolver with OpenAPI validation enabled + app = APIGatewayRestResolver(enable_validation=True) + + # GIVEN custom OpenAPI configuration + openapi_title = "My API" + openapi_myapi_version = "1.1.1-alpha" + openapi_version = "3.1.2" + openapi_description = "My descrition" + app.configure_openapi( + title=openapi_title, + version=openapi_myapi_version, + openapi_version=openapi_version, + description=openapi_description, + ) + + # WHEN we have a simple handler + @app.get("/") + def handler(): + pass + + # WHEN we get the schema + schema = json.loads(app.get_openapi_json_schema()) + + # THEN the schema should contain our custom configuration + assert schema["info"]["title"] == openapi_title + assert schema["info"]["version"] == openapi_myapi_version + assert schema["openapi"] == openapi_version + assert schema["info"]["description"] == openapi_description diff --git a/tests/functional/event_handler/_pydantic/test_openapi_params.py b/tests/functional/event_handler/_pydantic/test_openapi_params.py index 2cf77a7de08..5bcda896858 100644 --- a/tests/functional/event_handler/_pydantic/test_openapi_params.py +++ b/tests/functional/event_handler/_pydantic/test_openapi_params.py @@ -32,7 +32,7 @@ def handler(): raise NotImplementedError() schema = app.get_openapi_schema() - assert schema.info.title == "Powertools API" + assert schema.info.title == "Powertools for AWS Lambda (Python) API" assert schema.info.version == "1.0.0" assert len(schema.paths.keys()) == 1 From d3b3daac83f29c5c55b287675870d2c026334056 Mon Sep 17 00:00:00 2001 From: Leandro Damascena Date: Mon, 3 Mar 2025 17:17:13 +0000 Subject: [PATCH 2/4] Adding constants --- .../event_handler/api_gateway.py | 16 ++++++++++------ .../event_handler/openapi/constants.py | 1 + 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/aws_lambda_powertools/event_handler/api_gateway.py b/aws_lambda_powertools/event_handler/api_gateway.py index c553ca453e0..268026eac12 100644 --- a/aws_lambda_powertools/event_handler/api_gateway.py +++ b/aws_lambda_powertools/event_handler/api_gateway.py @@ -19,7 +19,11 @@ from aws_lambda_powertools.event_handler import content_types from aws_lambda_powertools.event_handler.exceptions import NotFoundError, ServiceError from aws_lambda_powertools.event_handler.openapi.config import OpenAPIConfig -from aws_lambda_powertools.event_handler.openapi.constants import DEFAULT_API_VERSION, DEFAULT_OPENAPI_VERSION +from aws_lambda_powertools.event_handler.openapi.constants import ( + DEFAULT_API_VERSION, + DEFAULT_OPENAPI_TITLE, + DEFAULT_OPENAPI_VERSION, +) from aws_lambda_powertools.event_handler.openapi.exceptions import RequestValidationError, SchemaValidationError from aws_lambda_powertools.event_handler.openapi.types import ( COMPONENT_REF_PREFIX, @@ -1546,7 +1550,7 @@ def __init__( def get_openapi_schema( self, *, - title: str = "Powertools for AWS Lambda (Python) API", + title: str = DEFAULT_OPENAPI_TITLE, version: str = DEFAULT_API_VERSION, openapi_version: str = DEFAULT_OPENAPI_VERSION, summary: str | None = None, @@ -1601,7 +1605,7 @@ def get_openapi_schema( # DEPRECATION: Will be removed in v4.0.0. Use configure_api() instead. # Maintained for backwards compatibility. # See: https://github.com/aws-powertools/powertools-lambda-python/issues/6122 - if title == "Powertools for AWS Lambda (Python) API" and self.openapi_config.title: + if title == DEFAULT_OPENAPI_TITLE and self.openapi_config.title: title = self.openapi_config.title if version == DEFAULT_API_VERSION and self.openapi_config.version: @@ -1751,7 +1755,7 @@ def _determine_openapi_version(openapi_version: str): def get_openapi_json_schema( self, *, - title: str = "Powertools for AWS Lambda (Python) API", + title: str = DEFAULT_OPENAPI_TITLE, version: str = DEFAULT_API_VERSION, openapi_version: str = DEFAULT_OPENAPI_VERSION, summary: str | None = None, @@ -1828,7 +1832,7 @@ def get_openapi_json_schema( def configure_openapi( self, - title: str = "Powertools for AWS Lambda (Python) API", + title: str = DEFAULT_OPENAPI_TITLE, version: str = DEFAULT_API_VERSION, openapi_version: str = DEFAULT_OPENAPI_VERSION, summary: str | None = None, @@ -1913,7 +1917,7 @@ def enable_swagger( self, *, path: str = "/swagger", - title: str = "Powertools for AWS Lambda (Python) API", + title: str = DEFAULT_OPENAPI_TITLE, version: str = DEFAULT_API_VERSION, openapi_version: str = DEFAULT_OPENAPI_VERSION, summary: str | None = None, diff --git a/aws_lambda_powertools/event_handler/openapi/constants.py b/aws_lambda_powertools/event_handler/openapi/constants.py index f5d72d47f7e..debe1d56736 100644 --- a/aws_lambda_powertools/event_handler/openapi/constants.py +++ b/aws_lambda_powertools/event_handler/openapi/constants.py @@ -1,2 +1,3 @@ DEFAULT_API_VERSION = "1.0.0" DEFAULT_OPENAPI_VERSION = "3.1.0" +DEFAULT_OPENAPI_TITLE = "Powertools for AWS Lambda (Python) API" From 3c99c8bd64a0afba5b5e9c32484941431c807359 Mon Sep 17 00:00:00 2001 From: Leandro Damascena Date: Mon, 3 Mar 2025 22:07:14 +0000 Subject: [PATCH 3/4] Refactoring examples --- .../_openapi_customization_metadata.md | 2 +- docs/core/event_handler/api_gateway.md | 8 ++--- .../src/customizing_api_metadata.py | 21 ++++++------- .../src/security_schemes_global.py | 31 +++++++++---------- .../security_schemes_global_and_optional.py | 29 +++++++++-------- .../src/security_schemes_per_operation.py | 29 +++++++++-------- 6 files changed, 58 insertions(+), 62 deletions(-) diff --git a/docs/core/event_handler/_openapi_customization_metadata.md b/docs/core/event_handler/_openapi_customization_metadata.md index 5a96db582cb..a69f53cd84d 100644 --- a/docs/core/event_handler/_openapi_customization_metadata.md +++ b/docs/core/event_handler/_openapi_customization_metadata.md @@ -1,6 +1,6 @@ -Defining and customizing OpenAPI metadata gives detailed, top-level information about your API. Here's the method to set and tailor this metadata: +Defining and customizing OpenAPI metadata gives detailed, top-level information about your API. Use the method `app.configure_openapi` to set and tailor this metadata: | Field Name | Type | Description | | ------------------ | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | diff --git a/docs/core/event_handler/api_gateway.md b/docs/core/event_handler/api_gateway.md index f2a60697740..fd6505ecccb 100644 --- a/docs/core/event_handler/api_gateway.md +++ b/docs/core/event_handler/api_gateway.md @@ -1053,7 +1053,7 @@ Include extra parameters when exporting your OpenAPI specification to apply thes === "customizing_api_metadata.py" - ```python hl_lines="25-31" + ```python hl_lines="8-16" --8<-- "examples/event_handler_rest/src/customizing_api_metadata.py" ``` @@ -1089,7 +1089,7 @@ Security schemes are declared at the top-level first. You can reference them glo === "Global OpenAPI security schemes" - ```python title="security_schemes_global.py" hl_lines="32-42" + ```python title="security_schemes_global.py" hl_lines="17-27" --8<-- "examples/event_handler_rest/src/security_schemes_global.py" ``` @@ -1097,7 +1097,7 @@ Security schemes are declared at the top-level first. You can reference them glo === "Per Operation security" - ```python title="security_schemes_per_operation.py" hl_lines="17 32-41" + ```python title="security_schemes_per_operation.py" hl_lines="17-26 30" --8<-- "examples/event_handler_rest/src/security_schemes_per_operation.py" ``` @@ -1105,7 +1105,7 @@ Security schemes are declared at the top-level first. You can reference them glo === "Global security schemes and optional security per route" - ```python title="security_schemes_global_and_optional.py" hl_lines="22 37-46" + ```python title="security_schemes_global_and_optional.py" hl_lines="17-26 35" --8<-- "examples/event_handler_rest/src/security_schemes_global_and_optional.py" ``` diff --git a/examples/event_handler_rest/src/customizing_api_metadata.py b/examples/event_handler_rest/src/customizing_api_metadata.py index cd9ced455d2..9297045ea1a 100644 --- a/examples/event_handler_rest/src/customizing_api_metadata.py +++ b/examples/event_handler_rest/src/customizing_api_metadata.py @@ -5,6 +5,15 @@ from aws_lambda_powertools.utilities.typing import LambdaContext app = APIGatewayRestResolver(enable_validation=True) +app.configure_openapi( + title="TODO's API", + version="1.21.3", + summary="API to manage TODOs", + description="This API implements all the CRUD operations for the TODO app", + tags=["todos"], + servers=[Server(url="https://stg.example.org/orders", description="Staging server")], + contact=Contact(name="John Smith", email="john@smith.com"), +) @app.get("/todos/") @@ -20,14 +29,4 @@ def lambda_handler(event: dict, context: LambdaContext) -> dict: if __name__ == "__main__": - print( - app.get_openapi_json_schema( - title="TODO's API", - version="1.21.3", - summary="API to manage TODOs", - description="This API implements all the CRUD operations for the TODO app", - tags=["todos"], - servers=[Server(url="https://stg.example.org/orders", description="Staging server")], - contact=Contact(name="John Smith", email="john@smith.com"), - ), - ) + print(app.get_openapi_json_schema()) diff --git a/examples/event_handler_rest/src/security_schemes_global.py b/examples/event_handler_rest/src/security_schemes_global.py index 3a3ef5ce6f4..762bc077596 100644 --- a/examples/event_handler_rest/src/security_schemes_global.py +++ b/examples/event_handler_rest/src/security_schemes_global.py @@ -12,6 +12,20 @@ logger = Logger() app = APIGatewayRestResolver(enable_validation=True) +app.configure_openapi( + title="My API", + security_schemes={ + "oauth": OAuth2( + flows=OAuthFlows( + authorizationCode=OAuthFlowAuthorizationCode( + authorizationUrl="https://xxx.amazoncognito.com/oauth2/authorize", + tokenUrl="https://xxx.amazoncognito.com/oauth2/token", + ), + ), + ), + }, + security=[{"oauth": ["admin"]}], # (1)!) +) @app.get("/") @@ -26,19 +40,4 @@ def lambda_handler(event, context): if __name__ == "__main__": - print( - app.get_openapi_json_schema( - title="My API", - security_schemes={ - "oauth": OAuth2( - flows=OAuthFlows( - authorizationCode=OAuthFlowAuthorizationCode( - authorizationUrl="https://xxx.amazoncognito.com/oauth2/authorize", - tokenUrl="https://xxx.amazoncognito.com/oauth2/token", - ), - ), - ), - }, - security=[{"oauth": ["admin"]}], # (1)! - ), - ) + print(app.get_openapi_json_schema()) diff --git a/examples/event_handler_rest/src/security_schemes_global_and_optional.py b/examples/event_handler_rest/src/security_schemes_global_and_optional.py index 2a890efd5e4..84e5b0fdfcd 100644 --- a/examples/event_handler_rest/src/security_schemes_global_and_optional.py +++ b/examples/event_handler_rest/src/security_schemes_global_and_optional.py @@ -12,6 +12,19 @@ logger = Logger() app = APIGatewayRestResolver(enable_validation=True) +app.configure_openapi( + title="My API", + security_schemes={ + "oauth": OAuth2( + flows=OAuthFlows( + authorizationCode=OAuthFlowAuthorizationCode( + authorizationUrl="https://xxx.amazoncognito.com/oauth2/authorize", + tokenUrl="https://xxx.amazoncognito.com/oauth2/token", + ), + ), + ), + }, +) @app.get("/protected", security=[{"oauth": ["admin"]}]) @@ -31,18 +44,4 @@ def lambda_handler(event, context): if __name__ == "__main__": - print( - app.get_openapi_json_schema( - title="My API", - security_schemes={ - "oauth": OAuth2( - flows=OAuthFlows( - authorizationCode=OAuthFlowAuthorizationCode( - authorizationUrl="https://xxx.amazoncognito.com/oauth2/authorize", - tokenUrl="https://xxx.amazoncognito.com/oauth2/token", - ), - ), - ), - }, - ), - ) + print(app.get_openapi_json_schema()) diff --git a/examples/event_handler_rest/src/security_schemes_per_operation.py b/examples/event_handler_rest/src/security_schemes_per_operation.py index 66770a787c7..04b5a4ba830 100644 --- a/examples/event_handler_rest/src/security_schemes_per_operation.py +++ b/examples/event_handler_rest/src/security_schemes_per_operation.py @@ -12,6 +12,19 @@ logger = Logger() app = APIGatewayRestResolver(enable_validation=True) +app.configure_openapi( + title="My API", + security_schemes={ + "oauth": OAuth2( + flows=OAuthFlows( + authorizationCode=OAuthFlowAuthorizationCode( + authorizationUrl="https://xxx.amazoncognito.com/oauth2/authorize", + tokenUrl="https://xxx.amazoncognito.com/oauth2/token", + ), + ), + ), + }, +) @app.get("/", security=[{"oauth": ["admin"]}]) # (1)! @@ -26,18 +39,4 @@ def lambda_handler(event, context): if __name__ == "__main__": - print( - app.get_openapi_json_schema( - title="My API", - security_schemes={ - "oauth": OAuth2( - flows=OAuthFlows( - authorizationCode=OAuthFlowAuthorizationCode( - authorizationUrl="https://xxx.amazoncognito.com/oauth2/authorize", - tokenUrl="https://xxx.amazoncognito.com/oauth2/token", - ), - ), - ), - }, - ), - ) + print(app.get_openapi_json_schema()) From 6a30901a1a4b25108e42207cc98b472cf76ec713 Mon Sep 17 00:00:00 2001 From: Leandro Damascena Date: Mon, 17 Mar 2025 15:44:00 +0000 Subject: [PATCH 4/4] Addressing Andrea's feedback --- aws_lambda_powertools/event_handler/openapi/config.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/aws_lambda_powertools/event_handler/openapi/config.py b/aws_lambda_powertools/event_handler/openapi/config.py index bae3804b39a..597362d1ef9 100644 --- a/aws_lambda_powertools/event_handler/openapi/config.py +++ b/aws_lambda_powertools/event_handler/openapi/config.py @@ -3,7 +3,11 @@ from dataclasses import dataclass from typing import TYPE_CHECKING, Any -from aws_lambda_powertools.event_handler.openapi.constants import DEFAULT_API_VERSION, DEFAULT_OPENAPI_VERSION +from aws_lambda_powertools.event_handler.openapi.constants import ( + DEFAULT_API_VERSION, + DEFAULT_OPENAPI_TITLE, + DEFAULT_OPENAPI_VERSION, +) if TYPE_CHECKING: from aws_lambda_powertools.event_handler.openapi.models import ( @@ -61,7 +65,7 @@ class OpenAPIConfig: ... ) """ - title: str = "Powertools for AWS Lambda (Python) API" + title: str = DEFAULT_OPENAPI_TITLE version: str = DEFAULT_API_VERSION openapi_version: str = DEFAULT_OPENAPI_VERSION summary: str | None = None