While using AWS Lambda + AWS API Gateway for hosting and accessing my Dash applications, I had a lot of issues getting the favicon to load for my apps. After extensive trial and error, I finally found a solution and wanted to share it here, since solutions to this problem are not available on the web so far.
Problem
Favicon data is not loaded in the browser because API Gateway blocks the binary data of the favicon.ico
file.
Context
- This solution was tested with Dash 2.3.1
- The application was deployed to AWS lambda and web access was arranged using AWS API Gateway
- The API type used was a REST API
- Server responses were handled using the aws-wsgi library.
- AWS applications were build and deployed using AWS SAM CLI, i.e.
sam build --use-container
andsam deploy
command-line commands.
Solution
The core issue is that binary data is blocked by the REST API by default. The problem is solved by 1. allowing the API to serve the correct binary types and 2. making sure that favicon is decoded as binary data.
Setting up API and Lambda resources
To deploy to AWS cloud with SAM CLI, you have to create a template.yaml
where you configure your AWS resources. Below is an excerpt of the template that I used in my application (fyi: below is not the complete template).
Resources:
DashApi:
Type: AWS::Serverless::Api
Properties:
BinaryMediaTypes:
- "image/*"
MyLambdaFunction:
Type: AWS::Serverless::Function
Properties:
Events:
DashEndpoint:
Type: Api
Properties:
Path: /{proxy+}
Method: ANY
RestApiId:
Ref: DashApi
The important thing here is to set BinaryMediaTypes
because this will tell your API which data to pass as binary data and which to pass as utf-8 encoded data. In this example I set all image types as binary. It is also possible to set all content types as binary with "*/*"
, or list specific image types only.
Handling the response with aws-wsgi
To access point to your application on the AWS Lambda side is done using a lambda_handler
function. A very straightforward way to do that is to use awsgi.response(app.server, event, context, base64_content_types)
from the aws-wsgi
library.
However, the call in this library will decode everything as utf-8 by default, unless it’s told otherwise specifically (see the topic I created previously). For this you have to set the base64_content_types
input parameter (list of strings). Below is a very simple implementation of a lambda_handler
that is enough to make your application running.
from your.dash.application.app import app
def lambda_handler(event, context):
base64_content_types = ['image/vnd.microsoft.icon', 'image/x-icon']
return awsgi.response(app.server, event, context, base64_content_types )
Note: the asterix wildcard doesn’t work in
base64_content_types
sinceawsgi
does a literal comparison ofContent-Type
with all entries in the list. So you have to list all desired base 64 content types explicitly.
Note 2: Icons are by default either
image/vnd.microsoft.icon
orimage/x-icon
MIME types. Even though Dash sets the HTML header for favicon tox-icon
doesn’t mean thatawsgi.response()
perceives it as that type. If yourfavicon
is of typepng
be sure to includeimage/png
to the list.
Conclusion
By correctly setting the above to parts, I was able to load favicon correctly. While this solution works for my particular context, it doesn’t mean that it cannot be ported to other ways of hosting Dash applications in AWS. If you have such examples feel free to share them below and letting us know how you adapted the above to make favicon work in your cloud context. I hope this information will save a lot of headaches and time for you.