Tutorial

Solve CORS once and for all with Netlify Dev

Published on June 28, 2019
author

swyx

Solve CORS once and for all with Netlify Dev

Access-Control-Allow-Headers and CORS

Say you’re a budding young (or young-at-heart!) frontend developer. You’d really love to smush together a bunch of third party APIs for your next Hackathon project. This API looks great: https://icanhazdadjoke.com/api! We’ll build the next great Dad Joke app in the world! Excitedly, you whip up a small app (these examples use React, but the principles are framework agnostic):

function App() {
  const [msg, setMsg] = React.useState("click the button")
  const handler = () =>
    fetch("https://icanhazdadjoke.com/", { headers: { accept: "Accept: application/json" } })
      .then((x) => x.json())
      .then(({ msg }) => setMsg(msg))

  return (
    <div className="App">
      <header className="App-header">
        <p>message: {msg}</p>
        <button onClick={handler}> click meeee</button>
      </header>
    </div>
  )
}

You excitedly yarn start to test your new app locally, and…

Access to fetch at 'https://icanhazdadjoke.com/' from origin 'http://localhost:3000' has been blocked by CORS policy: Request header field accept is not allowed by Access-Control-Allow-Headers in preflight response.

Oh no, you think, I’ve seen this before but how do I fix this again?

You google around and find this browser plugin and this serverside fix and this way too long MDN article and its all much too much for just a simple API request. First of all, you don’t have control of the API, so adding a CORS header is out of the question. Second of all, this problem is happening because you’re hitting an https:// API from http://localhost, which doesn’t have SSL, so the problem could go away once you deploy onto an https enabled domain, but that still doesn’t solve the local development experience. Last of all, you just wanted to get something up and running and now you’re stuck Googling icky security stuff on step 1.

Super frustrating. Now that more and more of the web is HTTPS by default, you’re just going to run into this more and more as you work on clientside apps (one reason server-side frameworks actually don’t even face CORS problems because they are run in trusted environments).

Netlify Dev, the Local Proxy Solution

If you’ve looked around long enough you’ll notice that CORS is a browser protection that completely doesn’t apply if you just made the request from a server you control. In other words, spin up a proxy server and all your problems go away. The only problem has been spinning up this proxy has been too hard and too costly. And that’s just for local dev; the deployed experience is totally different and just adds more complexity to the setup.

For the past few months I’ve been working on Netlify Dev, which aims to be a great proxy server for exactly this kind of usecase. It comes embedded in the Netlify CLI, which you can download:

$ npm i -g netlify-cli

Now in your project, if it is a popular project we support like create-react-app, Next.js, Gatsby, Vue-CLI, Nuxt and so on, you should be able to run:

# provide a build command and publish folder
# specific to your project,
# create a Netlify site instance, and
# initialize netlify.toml config file if repo connected to git remote
$ netlify init # or `ntl init`

# start local proxy server
$ netlify dev # or `ntl dev`

And you should see the proxy server run on localhost:8888 if that port is available.

If your project isn’t supported, you can write and contribute your own config, but it should be a zero config experience for the vast majority of people.

As of right now it is a local proxy server that just blindly proxies your project, nothing too impressive. Time to spin up a serverless function!

Creating a Netlify Function

At this point you should have a netlify.toml file with a functions field. You can handwrite your own if you wish, but it should look like this:

[build]
  command = "yarn run build"
  functions = "functions"
  publish = "dist"

You can configure each one of these to your needs, just check the Netlify docs. But in any case, now when you run:

$ netlify functions:create

the CLI shows you the list of function templates. Pick node-fetch and it will scaffold a new serverless function for you in /functions/node-fetch by default, including installing any required dependencies. Have a look at the generated files, but the most important one will be functions/node-fetch/node-fetch.js. By convention the folder name must match the file name for the function entry point to be recognized.

Great, so we now have a serverless Node.js function making our call to the API. The only remaining thing to do is to modify our frontend to ping our function proxy instead of directly hitting the API:

const handler = () =>
  fetch("/.netlify/functions/node-fetch", { headers: { accept: "Accept: application/json" } })
    .then((x) => x.json())
    .then(({ msg }) => setMsg(msg))

Getting rid of CORS in local development

Now when we run the proxy server again:

$ netlify dev # or ntl dev

And head to the proxy port (usually http://localhost:8888), and click the button…

message: Why can't a bicycle stand on its own? It's two-tired.

Funny! and we can laugh now that we have got rid of our CORS issues.

Deploying and Getting rid of CORS in production

When deploying, we lose the local proxy, but gain the warm embrace of the production environment, which, by design, is going to work the exact same way.

$ npm run build ## in case you need it
$ netlify deploy --prod ## this is the manual deploy process

And head to the deployed site (run netlify open:site).

Note: if you are deploying your site via continuous deployment from GitHub, GitLab or BitBucket, you will want to modify your netlify.toml build command to install function dependencies:

[build]
  command = "yarn build && cd functions/node-fetch && yarn"
  functions = "functions"
  publish = "dist"

Now you know how to spin up a function to proxy literally any API, together with using confidential API keys (either hardcoded, although don’t do this if your project is Open Source, or as environment variables) that you don’t want to expose to your end user, in minutes. This helps to mitigate any production CORS issues as well, although those are more rare.

If you have simple endpoints and files to proxy, you may also choose to use Netlify Redirect Rewrites to accomplish what we just did in one line, however it is of course less customizable.

That’s all there is to solving your CORS problems once and for all! Note that Netlify Dev is still in beta, if you ran into any hiccups or have questions, please file an issue!

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the authors
Default avatar
swyx

author

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
2 Comments


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Does this work with a static site (dist uploaded to Netlify) as well?

How do I work with these using digital ocean droplet in an nginx server.

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Featured on Community

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more