CORS

What if you don't have your entire application built using .arc? Maybe your front-end is hosted somewhere else, or you are starting out with a single Lambda function within a larger system.

For security reasons, browsers restrict cross-origin HTTP requests initiated from within scripts. For example, XMLHttpRequest and the Fetch API follow the same-origin policy. This means that a web application using those APIs can only request HTTP resources from the same domain the application was loaded from unless CORS headers are used.

To make a request from your main application to your cloud function, you'll need to enable CORS within the AWS console. Given the initial .arc file from the quickstart:

@app
testapp

@html
get /
  1. Go to API Gateway in the AWS console
  2. Add CORS
    • API Gateway → the .arc API name-production → Actions dropdown → Enable CORS
    • Repeat for staging
  3. Create API Key

Make a test request with API Key, ex:

curl --header "x-api-key: aA01etc1234567890234567890" https://example.execute-api.us-east-1.amazonaws.com/production/api/

Then, within your client side application, you might do something like:

var apiKey = 'aA01etc1234567890234567890'
var api = 'https://example.execute-api.us-east-1.amazonaws.com/production/api/'

window
  .fetch(api, {
    headers: { 'x-api-key': apiKey },
  })
  .then(function(res) {
    return res.json()
  })
  .then(function(json) {
    // { msg: 'hello world' }
    console.log(json)
  })
  .catch(function(err) {
    console.warn(err)
  })

Restricting domains

CORS isn't really used to restrict requests from certain domains, but you can do that within your function.

Continuing from the default quickstart /api endpoint, your API might operate differently based on the domain the request came from (other other headers):

var arc = require('@architect/functions')

// Example permitted domains
var permittedDomains = [
  'http://localhost:3000',
  'https://example.com'
]

function route(req, res) {
  console.log(JSON.stringify(req, null, 2))

  if (permittedDomains.includes(req.headers.origin)) {
    // Things that should only be done for permitted
    // requests. Get data, etc.
    res({
      json: { msg: `hello world` },
    })
  } else {
    // Send a different response to requests that
    // aren’t permitted to access this API
    res({
      json: { msg: `you don’t have permission to access` },
    })
  }
}

exports.handler = arc.json.get(route)

Conclusion

  • No longer getting CORS error
  • AWS handles the API keys
  • Your function checks the domain or other aspects of the header