Circumvent CORS when Accessing a Third-Party API using Netlify Functions

Jason Lengstorf
InstructorJason Lengstorf
Share this video with your friends

Social Share Links

Send Tweet

CORS limits websites from communicating with other domains without the full consent of both sites. Consuming data from a 3rd Party REST API makes it difficult since we can't properly configure the appropriate CORS headers. To solve this, we'll set up a proxy server to request the data using a Netlify function that avoids CORS altogether.

The Third-Party API that we'll be working with will provide the following data: id, name, favoriteSong for each corgi.

http://no-cors-api.netlify.app/api/corgis

We will also use node-fetch a light-weight module that brings the fetch API to fetch the data into our application.

Instructor: [0:00] Looking at our app right now, we can see that we're loading images and names, songs, photo credits, and a number of boops all into this app for display. However, right now, this is all hard coded. If we go and look at our public index, we can see, down here, all this information is being loaded from a hard coded object.

[0:23] If we wanted to get this from an API, or in our case, a few APIs, we're going to need to rewrite how this is done. We have an API available to us at nocoresapi.netlify.app/api/corgis, and this is going to give us back some data. It gives us back an ID, a name and a favorite song for each dog.

[0:47] The ID we're using also conveniently matches an unsplash photo ID so that we can pull that in from the Unsplash API. We will later create a custom database so that we can store the boop count. For now, let's get this loaded into our site.

[1:03] If we have this API, the first thing that we would expect to be able to do is to refactor this. Let's start. Let's get rid of all of this hard coded data. We're going to instead await fetch, and that means we need to make this an async function now. We're going to fetch a call to this API. When it comes back, we'll get the result, and we will process the result as JSON.

[1:38] If I save this, I can come out. Let's run that with my dev, so we can test this locally, so we don't have to deploy it. I have this running at 8888. Let's open that up, and look at the console. In the console, we can see the request was blocked by CORS policy.

[2:07] This is troublesome. In this example, we don't control this API. We don't have access to it, so we can't go and change this to make it CORS friendly. However, CORS only applies to in-browser requests, which means instead of worrying about fixing the API, we can work around using a serverless function.

[2:31] Let's create a new function. We'll call it loadCorgis. Inside of it, we're going to make that request. We set this up like every serverless function. It's going to export a handler, that's an async function. That's going to return an object. It'll have a status code of 200 for OK, and the body is going to be our corgis as JSON.

[2:57] We know we're going to JSON stringify our corgi data. If we come up here, we can set that up to start, so we'll say corgis, and maybe we'll make that an array like this for now. Now that we've created a new function, we're going to stop and restart. If I come back out here, I'm going to try going to localhost:8888. We'll go to netlify functions, loadCorgis, and I get back my empty array.

[3:33] If I were to put something in this array, like let's say, corgi true, and reload, we get back JSON corgi true. What I want to do is I want to load that corgi data. In order to do that, I want to be able to use the regular browser fetch API in node, which is what serverless functions run in. That does mean that we need to add one dependency, we're going to import fetch from node fetch.

[4:05] A node fetch is a zero dependency very fast, a small module that gives us a compatibility with the fetch API in the browser. I'm going to npm install node-fetch. This is going to show up right in our package here, in our top-level package. Now that we have this, it is accessible inside of our serverless function here.

[4:28] What I want to do is I'm going to start up here, I'm going to say const result equals await fetch. I'm going to pull this right out of here, actually. Let's copy paste that directly. I am now fetching this CORS API right here. Instead of returning corgis, let's just return this result. I'm going to restart netlify dev. Go to my browser, reload the page.

[5:04] Would you look at that? We've got back our code. We can see a couple of things are weird here. That doesn't quite do what we want but, turns out, that's because we haven't told the browser what to expect. Let's add a header for content type, and tell it to expect JSON. Save that.

[5:30] Remember, what we are getting is our em dashes were getting encoded. Let's reload. Now that we've told it that is JSON, the browser can properly decode that, and we get all of our special characters with the moon [inaudible] , and an em dash that all works as expected.

[5:47] Now that we've got a serverless function returning our corgi data, we can come in here, and let's rename this. We're going to send back our corgis, as expected. We'll do more with this later on, but for now, this is good to start. Instead of trying to load from this third party API, we're going to load from our own serverless function.

[6:08] This is local, so we can just go straight from the root, and we're going to load corgis like this. What this means is that we're now no longer fetching from a third-party API. We're fetching from our own proxy of that third-party API that uses the serverless function.

[6:28] The outcome should be the same, but the general process gets much simpler because we don't have to figure out how to work around CORS, we're able to just make that call from a server, and then return it through a serverless function, so we've eliminated that problem entirely.

[6:47] If we come back out here, we've got our server running. Let's go to localhost:8888, and we get some of our code. You'll notice we're missing our photos. We're missing the photo credit. We don't have a number of boops, but we are getting data, and that data, remember, has CORS restriction, so we wouldn't have been able to load that only in the browser.