Skip to content

Commit

Permalink
feat(event_handler): add decorator for HTTP HEAD verb (#4275)
Browse files Browse the repository at this point in the history
chore(ci): changelog rebuild (#4262)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Powertools for AWS Lambda (Python) bot <[email protected]>
Co-authored-by: Leandro Damascena <[email protected]>
  • Loading branch information
4 people authored May 6, 2024
1 parent f1cbcb3 commit 0412f66
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 11 deletions.
57 changes: 57 additions & 0 deletions aws_lambda_powertools/event_handler/api_gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -1222,6 +1222,63 @@ def lambda_handler(event, context):
middlewares,
)

def head(
self,
rule: str,
cors: Optional[bool] = None,
compress: bool = False,
cache_control: Optional[str] = None,
summary: Optional[str] = None,
description: Optional[str] = None,
responses: Optional[Dict[int, OpenAPIResponse]] = None,
response_description: str = _DEFAULT_OPENAPI_RESPONSE_DESCRIPTION,
tags: Optional[List[str]] = None,
operation_id: Optional[str] = None,
include_in_schema: bool = True,
security: Optional[List[Dict[str, List[str]]]] = None,
middlewares: Optional[List[Callable]] = None,
):
"""Head route decorator with HEAD `method`
Examples
--------
Simple example with a custom lambda handler using the Tracer capture_lambda_handler decorator
```python
from aws_lambda_powertools import Tracer
from aws_lambda_powertools.event_handler import APIGatewayRestResolver, Response, content_types
tracer = Tracer()
app = APIGatewayRestResolver()
@app.head("/head-call")
def simple_head():
return Response(status_code=200,
content_type=content_types.APPLICATION_JSON,
headers={"Content-Length": "123"})
@tracer.capture_lambda_handler
def lambda_handler(event, context):
return app.resolve(event, context)
```
"""
return self.route(
rule,
"HEAD",
cors,
compress,
cache_control,
summary,
description,
responses,
response_description,
tags,
operation_id,
include_in_schema,
security,
middlewares,
)

def _push_processed_stack_frame(self, frame: str):
"""
Add Current Middleware to the Middleware Stack Frames
Expand Down
20 changes: 10 additions & 10 deletions docs/core/event_handler/api_gateway.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ You can use named decorators to specify the HTTP method that should be handled i
--8<-- "examples/event_handler_rest/src/http_methods.json"
```

If you need to accept multiple HTTP methods in a single function, you can use the `route` method and pass a list of HTTP methods.
If you need to accept multiple HTTP methods in a single function, or support a HTTP method for which no decorator exists (e.g. [TRACE](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/TRACE)), you can use the `route` method and pass a list of HTTP methods.

```python hl_lines="15" title="Handling multiple HTTP Methods"
--8<-- "examples/event_handler_rest/src/http_methods_multiple.py"
Expand Down Expand Up @@ -524,12 +524,12 @@ Behind the scenes, the [data validation](#data-validation) feature auto-generate

There are some important **caveats** that you should know before enabling it:

| Caveat | Description |
| ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Swagger UI is **publicly accessible by default** | When using `enable_swagger` method, you can [protect sensitive API endpoints by implementing a custom middleware](#customizing-swagger-ui) using your preferred authorization mechanism. |
| **No micro-functions support** yet | Swagger UI is enabled on a per resolver instance which will limit its accuracy here. |
| You need to expose a **new route** | You'll need to expose the following path to Lambda: `/swagger`; ignore if you're routing this path already. |
| JS and CSS files are **embedded within Swagger HTML** | If you are not using an external CDN to serve Swagger UI assets, we embed JS and CSS directly into the HTML. To enhance performance, please consider enabling the `compress` option to minimize the size of HTTP requests. |
| Caveat | Description |
| ------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Swagger UI is **publicly accessible by default** | When using `enable_swagger` method, you can [protect sensitive API endpoints by implementing a custom middleware](#customizing-swagger-ui) using your preferred authorization mechanism. |
| **No micro-functions support** yet | Swagger UI is enabled on a per resolver instance which will limit its accuracy here. |
| You need to expose a **new route** | You'll need to expose the following path to Lambda: `/swagger`; ignore if you're routing this path already. |
| JS and CSS files are **embedded within Swagger HTML** | If you are not using an external CDN to serve Swagger UI assets, we embed JS and CSS directly into the HTML. To enhance performance, please consider enabling the `compress` option to minimize the size of HTTP requests. |

```python hl_lines="12-13" title="enabling_swagger.py"
--8<-- "examples/event_handler_rest/src/enabling_swagger.py"
Expand Down Expand Up @@ -835,8 +835,8 @@ As a practical example, let's refactor our correlation ID middleware so it accep

These are native middlewares that may become native features depending on customer demand.

| Middleware | Purpose |
| ------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| Middleware | Purpose |
| ------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| [SchemaValidationMiddleware](/lambda/python/latest/api/event_handler/middlewares/schema_validation.html){target="_blank"} | Validates API request body and response against JSON Schema, using [Validation utility](../../utilities/validation.md){target="_blank"} |

#### Being a good citizen
Expand Down Expand Up @@ -1053,7 +1053,7 @@ When you're describing your API, declare security schemes at the top level, and
OpenAPI 3 lets you describe APIs protected using the following security schemes:

| Security Scheme | Type | Description |
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [HTTP auth](https://www.iana.org/assignments/http-authschemes/http-authschemes.xhtml){target="_blank"} | `HTTPBase` | HTTP authentication schemes using the Authorization header (e.g: [Basic auth](https://swagger.io/docs/specification/authentication/basic-authentication/){target="_blank"}, [Bearer](https://swagger.io/docs/specification/authentication/bearer-authentication/){target="_blank"}) |
| [API keys](https://swagger.io/docs/specification/authentication/api-keys/https://swagger.io/docs/specification/authentication/api-keys/){target="_blank"} (e.g: query strings, cookies) | `APIKey` | API keys in headers, query strings or [cookies](https://swagger.io/docs/specification/authentication/cookie-authentication/){target="_blank"}. |
| [OAuth 2](https://swagger.io/docs/specification/authentication/oauth2/){target="_blank"} | `OAuth2` | Authorization protocol that gives an API client limited access to user data on a web server. |
Expand Down
8 changes: 7 additions & 1 deletion tests/functional/event_handler/test_api_gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,12 +291,16 @@ def delete_func():
def patch_func():
raise RuntimeError()

@app.head("/no_matching_head")
def head_func():
raise RuntimeError()

def handler(event, context):
return app.resolve(event, context)

# Also check the route configurations
routes = app._static_routes
assert len(routes) == 5
assert len(routes) == 6
for route in routes:
if route.func == get_func:
assert route.method == "GET"
Expand All @@ -308,6 +312,8 @@ def handler(event, context):
assert route.method == "DELETE"
elif route.func == patch_func:
assert route.method == "PATCH"
elif route.func == head_func:
assert route.method == "HEAD"

# WHEN calling the handler
# THEN return a 404
Expand Down

0 comments on commit 0412f66

Please sign in to comment.