CORS and request parsing in Begin.com functions

Jason Sackey
3 min readMay 4, 2020

--

Begin.com is a cloud infrastructure platform that’s a layer over some of Amazon Web Services, simplifying the development of web apps. “Serverless on easy mode!” Developing on begin.com means writing cloud functions (i.e. AWS Lambda) that turn into HTTP endpoints, and can access DynamoDB storage.

I used it for the first time a few days ago, to build a quick-and-dirty API for an experimental wiki project. I managed to read and write content (arrays of strings) in the storage. Getting it to work involved a few obstacles, described below… with fixes :)

Begin.com founder Ryan replied on Twitter and showed me some helpful stuff, so I’ll update the relevant sections of this post with better solutions.

1. CORS

Cross-origin resource sharing is when browsers load information from various servers. Security features in modern browsers let servers control when this is allowed to happen. This sometimes causes annoying obstructions during development, when working with multiple local servers. (I was serving my frontend and my local begin endpoints on two different ports.)

My API worked in Postman, but in Chrome I got this complaint

Access to fetch at 'http://localhost:3333/wiki/wiki' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

I found a post from the begin.com blog about enabling a cors boolean:

But that didn’t work.

What worked was adding this to the response header:

"Access-Control-Allow-Origin": "*"

Update: That blog post is outdated. But the cors boolean can be made to work. You need to use wrap the handler function with a helper, instead of exporting it directly.

let arc = require('@architect/functions');
async function http(req) {
return {
cors: true
}
}
exports.handler = arc.http.async(http);

2. Request parsing

Begin.com is built on the Architect serverless app framework. This provides some helper functions, including one for translating base64 encoded JSON strings into JS objects. In begin.com/Architect apps, all request body data comes in this format.

exports.handler = async function http(req) {
let body = arc.http.helpers.bodyParser(req);

The docs suggest that body, here, should be a JavaScript object. But I ended up with stuff like: eyJ0aXRsZSI6Indpa2kiLCJwYWdlIjpbInN0ZWFtIiwid2F0ZXIiLCJpY2UiLCJlbGVwaGFuIl19

What worked: using standard Node and JS functionality.

JSON.parse(Buffer.from(body, 'base64').toString('ascii'));

(btoa is the standard function for converting binary to ascii in browsers, not in NodeJS.)

Update: the bodyParser works fine as long as the request comes with the right content-type. Here’s the fetch call I was using:

fetch(ROOT + "/wiki", {
method: "POST",
body: JSON.stringify({
title,
page: newContent
}),
mode: "no-cors",
headers: {
"Content-Type": "application/json"
}
})

The no-cors option breaks it. It sends the wrong content-type and makes the response ‘opaque’ (i.e. useless). So, don’t use no-cors.

The CORS error situation again rears its ugly head.

Without ‘no-cors’, the request was being sent properly, but failed. I got errors with something called the CORS preflight request. This is sent before with the OPTIONS call, to check the features the endpoint says it supports.

Begin.com/Architect doesn’t let you set OPTIONS handlers for arbitrary paths. And luckily, we don’t need to. The solution is to listen for calls on the root path (‘/’) — the GET handler will greedily consume OPTIONS calls too. See here. Solution I implemented here. That response tells browsers that it’ll allow:

  • any origin (so you can make that more restricted/specific if you want)
  • any method from “GET, POST, OPTIONS”
  • whatever header(s) came with the request

This isn’t set by default in the CRUD starter todo app. It’ll probably be something I include as boilerplate for everything I make. I like open APIs and powerful frontends. But security considerations for certain use-cases would make other options more appropriate.

Despite these issues, begin.com seems nice to work with, and suitable for several of my project ideas.

Ideas including:

  • Wikis (particularly, something compatible with Federated Wiki)
  • News river
  • Dating site

--

--