You don't need that CORS request

You're working on a site, foobarbaz.app, and you've deployed your API to a subdomain at api.foobarbaz.app. The api. prefix feels like a nice touch because it's separated from the rest of your application.

Preflight Requests

Have you ever wondered what that OPTIONS request is executing before your actual GET/POST/PUT/DELETE when making requests to api.foobarbaz.app?

MDN Web Docs defines this as:

A CORS preflight request is a CORS request that checks to see if the CORS protocol is understood and a server is aware using specific methods and headers.

That definition makes sense once you understand what CORS is, seeing as it's self-referencing, but not so much before. Distilled down, it's a conversation between the browser and the API. It goes something like this:

Browser: "Hey API, can I make this request?"

API: "Hey Browser, sure."

Browser: "Thanks, API. Sending my request now"

The Web Hypertext Application Technology Working Group (WHATWG) CORS spec has an excellent walk-through of a basic scenario.

Cut your network requests in half

This conversation between the browser and the API is only necessary because our API at api.foobarbaz.app is not of the same origin as foobarbaz.app, specifically our hostname is now different. Port (:443, :80, etc) and protocol (HTTP, HTTPS) also follow the same logic as hostname, so any differences in the page's hostname, port, and protocol and a request executed on the page will require a CORS request. web.dev's Understanding "same-site" and "same-origin" does a great job of breaking down the parts of a URL.

You'll notice that a header, sec-fetch-site, is attached to any XHR request in Firefox and Chrome which will indicate whether this was a same-origin request or not.

Below is an example of cross origin request headers in Firefox. Note the Sec-Fetch-Site: cross-site. You can read more about Sec-Fetch-Site here on MDN.

If you're using a service, like Fastly or Cloudflare, to proxy to your application or if you have a proxy setup — this shouldn't be an invasive change since the aim is simply to create an alias on the hostname where the original application loaded. Routing https://api.foobarbaz.app to https://foobarbaz.app/api and moving over the JavaScript clients using the api. subdomain will cut your network traffic in half.

Context

While working at meetup.com, I worked on a team focused on improving p95 latencies, which is actually interesting, engaging work. One afternoon another engineer and myself were having a hard time identifying low-effort, high impact changes when we stumbled across the 40-90ms each network request was making from the browser for preflight requests. In one afternoon, we removed our CORs requests — a change that drastically improved the desktop and mobile web's experience.

© Nick Olinger 2023