3

I'm trying to build an RESTful service in Amazon Web Service, using API Gateway and Lambdas. One of the API Gateway method is intended to return a single record from a DynamoDB table of a corresponding resource from S3. This resource is an XML file, but I don't know how can I return this content from the Lambda function in a way that its served as a downloadable file. I'm using Python to code the lambdas, and so far it looks like this:

import json
from lxml import etree

def get_item_handler(event, context):
    # Validate request
    # ...
    # End validation

    logger.info('Querying by id:{0}'.format(event["id"]))
    query_kwargs = {
        'Select': "ALL_ATTRIBUTES",
        'Limit': event["PageSize"] if "PageSize" in event else settings.DEFAULT_PAGE_SIZE,
        'KeyConditionExpression': Key('id').eq(event["id"])
    }

    dynamodb = boto3.resource('dynamodb')
    table = dynamodb.Table(settings.TABLE_NAME)
    response = table.query(**query_kwargs)

    if "format" in event and event["format"] and response["Items"]:
        response_format = event["format"].lower()
        item = json.loads(json.dumps(response['Items'], cls=DecimalEncoder))[0]
        if response_format == "xml":    
            s3_path = get_item_path(item) # Form path to the item in S3
            resource = os.path.join(s3_path , item["resource"])
            local_file = '/tmp/{0}'.format(item["resource"])
            s3_client = boto3.client('s3')
            transfer = S3Transfer(s3_client)
            transfer.download_file(settings.BUCKET_NAME, resource, local_file)
            xml = etree.parse(local_file)
            return etree.tostring(xml)

    return json.dumps(response['Items'], cls=DecimalEncoder)

The API Gateway is set to application/xml, and it returns an string with the xml content, but this is not what I want, I need to return the XML as a file.

2 Answers 2

5

As Zanon already responded, you need to set response headers for Content-Type: application/xml and Content-Disposition: attachment; filename="myfile.xml".

It sounds like you already have the Content-Type: application/xml working.

To set the Content-Disposition: attachment; filename="myfile.xml" header, first go to the Method Response page for your method. Under "HTTP Status", click the triangle/arrow to the left of the 200 line to expand it. Next click on "Add Header". Enter Content-Disposition as the header name and click on the checkbox icon to save. This declares that the response will send the Content-Disposition header. Next you have to map a value to the header. To do this, go to the Integration Response page for your method. Expand the 200 line and the Header Mappings section. Under Header Mappings you should now see the Content-Disposition. Click on the Mapping value space to the right of Content-Disposition to define a mapping for it. In this case we can just use a constant value, so enter 'attachment; filename="myfile.xml"'. Be sure to include the single quotes. Then click the checkmark icon to save.

You should now be able to test your API method via the console and see the Content-Disposition header being set to attachment; filename="myfile.xml". Remember to re-deploy your API go get the changes to take effect outside of the console.

Sign up to request clarification or add additional context in comments.

Comments

2

For a downloadable file, you need to set two response headers:

Content-Type: application/xml
Content-Disposition: attachment; filename="myfile.xml"

This setting is done in the API Gateway. You said that you've already configured the Content-Type, so I believe that what you need now is to configure the Content-Disposition.

1 Comment

How can I set the Content-Disposition?, I only find the Content-Type setting. Thanks

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.