Eric Wang
Eric Wang

Reputation: 161

How to build an image download API by AWS Chalice on Lambda?

I want to build an image download API by AWS Chalice on Lambda which the image is stored on AWS S3. However, the image downloaded through API can only be opened by running chalice on local, and could not open the file download from API deployed on AWS.

Since our s3 bucket is private and we want the download link to be available in long term (at least over a month). Hence, we throw our data through chalice api not s3 presigned url.

Here is my code

@app.route("/img/download", methods=["GET"])
def download_image_api():
    def download_img():
    
    bucket = "my-bucket-name"
    key = "my-key-name"
    filename = "imgae-file-name"
    filepath = f"/tmp/{filename}"

    # download imgae to lambda
    s3 = boto3.client(
        resource="s3",
        region_name=config.AWS_REGION_NAME,
        aws_access_key_id=config.ACCESS_ID,
        aws_secret_access_key=config.SECRET_KEY
    )
    s3.download_file(bucket, key, filepath)

    # build headers
    file_size = os.path.getsize(filepath)
    headers = {
        'Content-Type': 'application/octet-stream',
        'Content-Disposition': f'attachment; filename={filename}',
        'Content-Length': str(file_size)
    }

    # build body
    f = open(filepath, 'rb')
    body = f.read()

    return Response(body=body, headers=headers)

and the error message is

enter image description here

Upvotes: 0

Views: 55

Answers (1)

Eric Wang
Eric Wang

Reputation: 161

In the end, we change our way to download the image. We generate a temporary presigned url from S3, and use directions to re-locate our image download URL.

@app.route("/img/download", methods=["GET"])
def download_image_api():
    def download_img():
    
    bucket = "my-bucket-name"
    key = "my-key-name"
    filename = "imgae-file-name"
    filepath = f"/tmp/{filename}"

    # get temporary presigned url
    s3 = boto3.client(
        resource="s3",
        region_name=config.AWS_REGION_NAME,
        aws_access_key_id=config.ACCESS_ID,
        aws_secret_access_key=config.SECRET_KEY
    )
    presigned_utl = s3.generate_presigned_url(
        'get_object', 
        Params={
            'Bucket': bucket_name,
            'Key': key
        }
        ExpiresIn=3600
    )

    # build headers
    headers = {
        "Location": presigned_url
    }

    return Response(
        body=json.dumps(dict()),
        headers=headers,
        status_code=302
    )

Hence, users can still download image directly from API.

Upvotes: 0

Related Questions