Upload and download file through same API gateway with presignedURLs

Viewed 23

How to:

  1. Link the output of a lambda function (presignedURL) to an API gateway?
  2. Forward the presignedURL to the browser of a user, such that a download is triggered?

A user uploads a csv file through an API to s3. After a lambda function transforms the data, a pdf file is sent to the user's browser.

So, I want to include a download function in the below app.js which facilitates the uploading function of the AWS API Gateway. Any help is welcomed how the following functionalities can be included:

  • Send output of lambda function (presignedURL, when available max. 30sec) to the API gateway;
  • Send presignedURL to the browser of the user, such that a download is triggered.

// Upload function

const AWS = require('aws-sdk')
AWS.config.update({ region: process.env.AWS_REGION })
const s3 = new AWS.S3()

const URL_EXPIRATION_SECONDS = 300

// Main Lambda entry point
exports.handler = async (event) => {
  return await getUploadURL(event)
}

const getUploadURL = async function(event) {
  const Key = `test.csv`

  // Get signed URL from S3
  const s3Params = {
    Bucket: process.env.UploadBucket,
    Key,
    Expires: URL_EXPIRATION_SECONDS,
    ContentType: 'text/csv',

    // This ACL makes the uploaded object publicly readable. You must also uncomment
    // the extra permission for the Lambda function in the SAM template.

    // ACL: 'public-read'
  }

  console.log('Params: ', s3Params)
  const uploadURL = await s3.getSignedUrlPromise('putObject', s3Params)

  return JSON.stringify({
    uploadURL: uploadURL,
    Key
  })
}

// Download function (pdf)

const Downloadfunc ...
   
    // Get presignedURL from lambda function output

    // Send presignedURL to the browser of the user that triggers a download
... 

      </div>
      <h2 v-if="uploadURL">File uploaded to bucket.</h2>
    </div>
  
    <script>

      const API_ENDPOINT = 'https://*****.execute-api.us-east-1.amazonaws.com/uploads'
      
 ...

1 Answers

That is not possible in the way you want it to work. The lambda is triggered by S3 and does not know anything about the API gateway and neither does the API gateway know anything about the specific lambda execution.

What you need here is either have the lambda follow a pattern where to store the uploaded file, based on the original file, e.g. the same UUID filename, just with a .pdf at the end. And then have the user call the download function which checks if the pdf is already there and returns / redirects to a presigned url if it is, and an error / "wait a few seconds" message if it does not yet exist.

Alternatively you need some kind of database that stores the information where the target file is located and have the rest of the logic exactly the same.

In any case you need some kind of identification of the file, e.g. a UUID for the actual file name or for the "file upload process". Using that id can the client then request a download if the server finished processing it already.

A different approach would be e.g. to use websockets to actually notify the client of a finished upload but that is just a more fancy way to do what I already described.

Related