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).
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!
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))
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.
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.
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.
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.