What is CORS? Why Can't I consume this endpoint?
Cross-Origin Resource Sharing, or CORS, is a browser mechanism that enables controlled access to resources located outside of a given domain. This is really useful for when you have assets or endpoints that you only want accessible from certain domains. I recently really wanted to use a public API for a web project, but that API wasn't accessible over the front-end so I needed to get a little creative for how I was going to retrieve that data.
The API in question is from the Centers for Disease Control and Prevention to get COVID-19 related data (cases, deaths, and vaccinations) for United States states and territories. The COVID-19 API can be hit directly, but trying to load it over the front-end, like in my initial CodePen demo, led to the following error:
While this was an initial hurdle, it was also the inspiration to figure out how to resolve this. I can't hit this endpoint over the front-end, but maybe I could leverage the backend to retrieve the data? After all, I can CURL the endpoint and get a response:
Netlify Serverless Functions
I'm a huge proponent of the JAMstack and putting more horsepower into our developer tooling instead of the end user's browser. To use this COVID API as an example, instead of every user visiting my app hitting that API endpoint to pull in data, what if I hit it for them and serve them up a static HTML page? That would reduce latency, improve page speed, and I'm sure the CDC would appreciate me not using all of their bandwidth in the event that my app takes off.
To do this, we can leverage Netlify Serverless functionsc to hit the API, scrape it, manipulate any data if we need to, and then re-return it to our application on build time to scaffold out our app. In this particular instance, I am leverage Nuxt.js, a static-site generator built on top of Vue. Essentially, whenever I push code or a deploy is triggered, my Nuxt application will run commands to hit the API, generate static files, and deploy those static files to Netlify.
Getting started with Serverless Functions
Serverless functions are basically AWS Lambda functions that run outside of your application, even though they are in your codebase. So if your app is like mine and is composed entirely of front-end code (no PHP, asp, .net, python, etc) you can leverage these serverless functions to do some serious heavy lifting.
To get started with serverless functions in Netlify, just create a
Every function in Netlify should be an exported module that returns an object with the
body response of that call. For example, if I wanted to create an endpoint for rolling a 20-sided die, like
netlify/functions/d20.js with the following:
I could then hit my app, like at https://dice-rollin.netlify.app/.netlify/functions/d20 (this is the only endpoint so far but maybe I'll roll this out into a fully-featured DnD API later...)((I set up this dice rolling demo endpoint for this article and it no joke took me less than 5 minutes)) and it would return the JSON object:
This is pretty powerful. Now that we have our endpoint working, we can start to add in some more processing power and leverage Node to get the data we really need.
Using Node Fetch to hit an Endpoint
Now that we have our endpoint working in Netlify, we can start to do some real coding. Below we'll leverage Node Fetch to hit our endpoint, await a response, and once we have it, relay that response back to us. I'll start by creating a
Next, we'll make sure Node Fetch is part of our project:
$ npm install node-fetch --save-dev
From there, we can get to work:
Now when we hit our endpoint, we'll get a 200 response back with all of the data that was in the CDC API, but now it is being returned from our own app!
Using this data in our Nuxt application
For my project, https://covidcasesbythenumbers.com/, I wanted to generate unique pages for each state and territory. To do this, I created another node js file to hit that endpoint, save it as a local file, and then tell Nuxt at build time to loop over it and generate a page for each state object in the response.
I created a dynamicpages.js file (this is similar to another one of my blog posts where I do the same thing with GraphQL) that will hit our API, and save out the response in a local file, and then we'll tell Nuxt about it to generate our routes.
First, though, let's create that local file. Create a new
dynamicpages.js file and in there lets do something like this:
Now whenever we, or our Netlify build process, generate pages for our site, it will generate static page routes, as well as all of our states and territories routes.
Passing Data with Payloads
In the above code sample you'll notice that when we return a page to our routes, we also pass it a payload. In the above example, we pass the whole state object from that state to the route. In Nuxt, our requests that match a certain route will also pass along that payload to use within the template.
For our COVID-19 example, we have a template called
pages/_id.vue . In this file we have our standard Vue properties to render it out as a component:
However, at this point, our component is expecting us to pass in the data via a prop. Instead, we can tell this component that it should actually take its data from the payload:
The Nuxt asyncData hook will set the
state prop based on the payload! So instead of a user hitting our URL, then our API fetches the data, all of this is instead hours or days in advance when our site builds.
This works out of the box for when you run
nuxt generate but won't work when running locally with
npm run dev because the payload isn't being passed off. We can fix this by returning a hardcoded example for development if the payload doesn't exist:
Benefits of Going Serverless
There is so much about this approach that gets me excited. Not only does this help us get around our CORS-enabled endpoints, but it also puts the power into the hands of front-end developers. We can manipulate the data or crunch the data on the backend to provide a faster experience for our users, or like I'm doing in my app, using one endpoint to hit multiple endpoints and combine it all into a singular API request based on my specifications. I can leverage my hosting provider to do all the heavy lifting while offering an optimal experience to my end users.
Looking to go serverless or embrace the JAMstack? I'd love to hear from you.