If you've ever built a web app that had to request data from a different domain, you've probably had to wrap your head around the browser's same-origin policy and CORS.
In this article we'll learn how to get around CORS issues using Create React App's proxying capabilities.
The Problem
If our app is hosted under a certain domain (e.g. domain1.com
), and it tries to make a request to an API that lives under a different domain (e.g. domain2.com
), then the browser's same-origin policy kicks in and blocks the request.
CORS is a feature that allows domain2.com
to tell the browser that it's cool for domain1.com
to make requests to it, by sending certain HTTP headers.
However, CORS can be tricky to get right, so sometimes people avoid it altogether by serving their frontend and backend under the same domain in production.
Create React App allows us to replicate this setup in development, so that we don't have to deal with CORS there either. It provides two options to do so: one that's very straightforward but is not very flexible, and one that requires a bit more work but is very flexible.
Automatic Proxying
We can tell Create React App to intercept requests to unknown routes and send them to a different domain, using the proxy
option in package.json
. It looks something like this:
{
"name": "flickr-client",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-scripts": "^2.1.8"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"proxy": "http://localhost:4000"
}
When we start our app, it will be served under http://localhost:3000
. If we request the root path /
, then Create React App will respond with the corresponding HTML for our app. But if we were to request a different path like /api
, Create React App would transparently forward it to http://localhost:4000/api
.
If we look at the network requests in your browser dev tools, we'll see that the request was made to http://localhost:3000/api
, but it was in fact served by http://localhost:4000/api
without the browser knowing.
It can't get easier than this!
Manual Proxying
If we need more control over how these cross-domain requests get made, we have another option, which is to create a file src/setupProxy.js
that looks like this:
module.exports = function(app) {
// ...
};
That function receives app
, an instance of an Express app, so we can do whatever we want with it.
For example, we can use a middleware like http-proxy-middleware
to proxy requests just like we did with the proxy
option:
const proxy = require("http-proxy-middleware");
module.exports = app => {
app.use(
"/api",
proxy({
target: "http://localhost:4000",
changeOrigin: true
})
);
};
But we can go further, and use http-proxy-middleware
's options like pathRewrite
to change the path of the request:
const proxy = require("http-proxy-middleware");
module.exports = app => {
app.use(
"/api",
proxy({
target: "http://localhost:4000",
changeOrigin: true,
pathRewrite: {
"^/api": "/api/v1"
}
})
);
};
With this configuration, a request made to http://localhost:3000/api/foo
will be forwarded to http://localhost:4000/api/v1/foo
.
We could also add a logger like morgan
while we're at it:
const proxy = require("http-proxy-middleware");
const morgan = require("morgan");
module.exports = app => {
app.use(
"/api",
proxy({
target: "http://localhost:4000",
changeOrigin: true,
pathRewrite: {
"^/api": "/api/v1"
}
})
);
app.use(morgan('combined'));
};
So now every time a request gets made to our proxy, it will get logged to the console.
The possibilities are truly endless.
Conclusion
If your web app needs to request data from a different domain, and you want your development environment to mimic a production configuration where frontend and backend are served from the same domain, make sure to take a look at the proxy
and src/setupProxy.js
options of Create React App. They'll make development of your app much easier!
Further Reading
Looking to learn more about developing apps for React with Create React App? Check out the posts below, and don't forget to visit our All Things React post for a wide range of info and pointers on everything React.
Top comments (0)