Skip to content

Instantly share code, notes, and snippets.

@msankhala
Created March 26, 2025 12:01
Show Gist options
  • Save msankhala/b20ad8621398ec86b72df822168332bb to your computer and use it in GitHub Desktop.
Save msankhala/b20ad8621398ec86b72df822168332bb to your computer and use it in GitHub Desktop.
CORS issue Content-Disposition header issue serverless
def export_recipes_to_csv(event):
"""
Exports recipes to a CSV file.
:param recipe_list: List of recipe dictionaries.
:param filename: Output CSV file name.
"""
body = json.loads(event.get("body", "{}"))
# Get the list of recipe IDs from the request body.
recipe_ids = body.get("recipe_ids", []) # List of recipe IDs.
filename = f"/tmp/exported_recipes_{datetime.now().strftime('%Y-%m-%d-%H-%M-%S')}.csv"
if recipe_ids:
try:
if not isinstance(recipe_ids, list):
raise ValueError("recipeIds must be a list.")
# Validate all items are strings or numbers
for recipe_id in recipe_ids:
if not isinstance(recipe_id, (str, int, float)):
raise ValueError(
f"Invalid recipeId: {recipe_id}. Must be a string or number."
)
# Convert all IDs to string format
recipe_ids = [str(recipe_id) for recipe_id in recipe_ids]
except (json.JSONDecodeError, ValueError, TypeError) as e:
return {
"error": f"Invalid 'recipeIds' format: {str(e)}"
}, HTTPStatus.BAD_REQUEST
recipe_list = (
food_store.get_by_ids(recipe_ids) if recipe_ids else food_store.get_all()
)
if not recipe_list:
print("No recipe data available to export.")
return
csv_buffer = io.StringIO()
writer = csv.writer(csv_buffer)
for index, recipe in enumerate(recipe_list):
# Loop through recipe and add rows to the CSV file.
writer.writerow(
[
recipe_id,
name,
source,
total_time,
servings,
ingredients,
steps,
additional_notes,
]
+ macro_nutrition_values
+ micro_nutrition_values
+ category_dietary_values
+ category_exclusion_values
+ category_course_values
+ category_meal_values
+ category_advanced_values
+ category_other_values
)
csv_content = csv_buffer.getvalue()
csv_buffer.close()
print(f"Recipes exported to: {filename}")
return {
"statusCode": HTTPStatus.OK,
"headers": {
"Content-Type": "text/csv",
"Content-Disposition": f"attachment; filename=\"{filename}\"",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization, X-Requested-With, X-Api-Key, X-User-Id,",
# Allow the browser to access the Content-Disposition header.
# This will fix the CORS issue when downloading the file.
"Access-Control-Expose-Headers": "Content-Disposition",
},
"body": csv_content,
}
custom:
lambda_env: &lambda_env
IMAGE_URL: ${self:custom.s3_url}
IMAGE_URL_THUMBNAILS: ${self:custom.s3_url}thumbnails/
MEAL_PLAN_TIMEOUT: 5000
S3_BUCKET_NAME: ${self:custom.s3_bucket_name}
S3_IMAGE_BUCKET_NAME: ${self:custom.s3_image_bucket_name}
JWT_KEY: ${env:JWT_KEY}
JWT_ALGO: "RS256"
authorizer: &jwt_authorizer
name: authorizerFunc
identitySource: method.request.header.Authorization
type: token
resultTtlInSeconds: 300
cors: &cors_policy
origins:
- http://localhost:3000
- https://localhost:3000
- http://myproject.ddev.site
- https://myproject.ddev.site
- http://dev.myproject.org
- https://dev.myproject.org
headers:
- Content-Type
- X-Amz-Date
- Authorization
- X-Api-Key
- X-Amz-Security-Token
- X-Amz-User-Agent
- X-User-Id
- Access-Control-Allow-Origin
- Access-Control-Allow-Headers
- x-user-id
- Content-Disposition
allowCredentials: false
functions:
exportRecipe:
handler: endpoints/export_recipe.handler
environment: *lambda_env
package: *meal_plan_excludes
layers:
- !Ref RequirementsLambdaLayer
# @todo: Remove the dependency on the OrToolsPandas layer, if it is not
# needed.
- !Ref OrToolsPandasLambdaLayer
events:
- http:
method: POST
path: /export-recipe
cors: *cors_policy
private: true
authorizer: *jwt_authorizer
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment