Closed pavitra-infocusp closed 6 months ago
Thanks for opening your first issue here! We'll come back to you as soon as we can. In the meantime, check out the #python channel on our Powertools for AWS Lambda Discord: Invite link
Thank you for the report @pavitra-infocusp - looking into this shortly today.
I might be missing something but I can't reproduce - here's an endpoint I've created to test (code at the bottom): https://pm5mz0wx61.execute-api.eu-west-1.amazonaws.com/Prod/todos
Questions
is this also happening on pre-flight operations OPTIONS
? Could you share how you setup API Gateway?
I've used both cURL and a browser JS test.
curl -s -I -H "Origin: https://docs.powertools.aws.dev" -X GET "https://pm5mz0wx61.execute-api.eu-west-1.amazonaws.com/Prod/todos"
Infra Cors SETUP
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: >
Complete infra to reproduce lack of CORS headers in #3849
Globals:
Function:
Timeout: 60
MemorySize: 512
Tracing: Active
Runtime: python3.11
Architectures:
- x86_64
Environment:
Variables:
POWERTOOLS_METRICS_NAMESPACE: TodoApp
LOG_LEVEL: INFO
TZ: "Europe/Amsterdam"
Api:
TracingEnabled: true
Cors: # see CORS section: https://docs.powertools.aws.dev/lambda/python/latest/core/event_handler/api_gateway/#cors
AllowOrigin: "'*'"
AllowHeaders: "'Content-Type,Authorization,X-Amz-Date'"
MaxAge: "'5'"
Resources:
#####################################################
# API Todos
#
# Flow: API Gateway -> Lambda
# |
# v
# /todos -> Lambda
#
#####################################################
GetTodosFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html
Properties:
Handler: app.lambda_handler
CodeUri: todo_api
Events:
HelloPath:
Type: Api
Properties:
Path: /todos
Method: GET
TodoById:
Type: Api
Properties:
Path: /todos/{todo_id}
Method: GET
CreateTodo:
Type: Api
Properties:
Path: /todos
Method: POST
SwaggerUI:
Type: Api
Properties:
Path: /swagger
Method: GET
SwaggerUICSS:
Type: Api
Properties:
Path: /swagger.css
Method: GET
SwaggerUIJS:
Type: Api
Properties:
Path: /swagger.js
Method: GET
# Powertools env vars: https://awslabs.github.io/aws-lambda-powertools-python/#environment-variables
Environment:
Variables:
POWERTOOLS_SERVICE_NAME: TodoAPI
# POWERTOOLS_DEV: true
Outputs:
GetTodosFunction:
Description: "Hello World Lambda Function ARN"
Value: !GetAtt GetTodosFunction.Arn
TodoEndpoint:
Description: "API Gateway endpoint URL for Prod environment for Todos"
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod"
GetTodosAPI:
Description: "API Gateway endpoint URL to fetch todos"
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/todos"
Code used
from typing import Annotated, Optional
import requests
from aws_lambda_powertools import Logger, Tracer
from aws_lambda_powertools.event_handler import (
APIGatewayRestResolver,
CORSConfig,
)
from aws_lambda_powertools.event_handler.openapi.params import Query
from aws_lambda_powertools.logging import correlation_paths
from aws_lambda_powertools.utilities.typing import LambdaContext
from aws_lambda_powertools.utilities.parser import Field, BaseModel
tracer = Tracer()
logger = Logger()
cors = CORSConfig(max_age=2) # short enough to avoid caching issue
app = APIGatewayRestResolver(enable_validation=True, cors=cors)
app.enable_swagger(path="/swagger")
class Todo(BaseModel):
userId: int
id_: Optional[int] = Field(alias="id", default=None)
title: str
completed: bool
@app.get("/todos")
@tracer.capture_method
def get_todos(
completed: Annotated[str | None, Query(min_length=4)] = None
) -> list[Todo]:
url = "https://jsonplaceholder.typicode.com/todos"
if completed is not None:
url = f"{url}/?completed={completed}"
todo = requests.get(url)
todo.raise_for_status()
return todo.json()
@logger.inject_lambda_context(correlation_id_path=correlation_paths.API_GATEWAY_REST)
@tracer.capture_lambda_handler
def lambda_handler(event: dict, context: LambdaContext) -> dict:
ret = app.resolve(event, context)
# Logging response to be triple sure Event Handler is appending CORS headers
logger.info("Returning response", response=ret)
return ret
Actually, it's not an issue with Powertools at all. It failed on the preflight requests stating CORS issue. Since I'm building a Chrome extension, Chrome doesn't set the Origin
header with the request, unless the URL is specified in the host_permissions
in the manifest. Sorry for the misunderstanding.
This issue is now closed. Please be mindful that future comments are hard for our team to see.
If you need more assistance, please either tag a team member or open a new issue that references this one.
If you wish to keep having a conversation with other community members under this issue feel free to do so.
I'm glad you found out @pavitra-infocusp -- better safe than sorry :) no worries from our side. Have an awesome day ahead with your new extension!
Thanks for your support!
Expected Behaviour
The responses should return with CORS headers set.
Current Behaviour
The CORS headers are missing, unless, explicitly set using
Response
class.Code snippet
Possible Solution
Inject the Origin header to the
event
param beforeapp.resolve()
call.Steps to Reproduce
Uncomment the line after
lambda_handler
function declaration, and run the code locally.Powertools for AWS Lambda (Python) version
latest
AWS Lambda function runtime
3.12
Packaging format used
Lambda Layers
Debugging logs
Expected behaviour: