Tim
Tim

Reputation: 43

Making CORS API requests with create-react-app and webpack - no express

I'm trying to make API calls without disabling CORS in my browser. The app was created using react-create-app. It is using webpack, and webpackDevServer for dev. All the answers I found on here say to put the following code into my webpack.config file.

devServer: {
      headers: {
        "Access-Control-Allow-Origin": "*",
        "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
        "Access-Control-Allow-Headers": "X-Requested-With, content-type, Authorization"
      }
  }

However, I've tried it in a number of different places and it doesn't work.

I continue to get the error:

Failed to load resource: the server responded with a status of 500 ()

and

Failed to load ... Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 500.

I also attempted to change my calls from axios calls to fetch calls

return fetch(process.env.REACT_APP_API_URL + "/prod/user", {
    mode: 'no-cors',
    credentials: 'include',
    method: "GET",
    headers: {
        "x-api-key": process.env.REACT_APP_API_KEY
    }
})
.then(response => {
   return response.json()
})
.then(resp => dispatch(receiveUsers(resp.data)))
.catch(error => {console.log(error)})

That got me closer but the console now is returning

Response {type: "opaque", url: "", redirected: false, status: 0, ok: false, …}

How do I get around this CORS issue? Thanks in advance for your help!

Response/Request Headers

Upvotes: 4

Views: 18985

Answers (3)

Fareed Alnamrouti
Fareed Alnamrouti

Reputation: 32154

the best option is to use a proxy especially if you use external API's or multiple API's. Just install proxy-middleware and create the file src/setupProxy.js and inside the file, you can add similar code to this:

const proxy = require('proxy-middleware');

module.exports = app => {
  // setup proxies
  // 1st api
  app.use("/etherscan", proxy("http://api.etherscan.io/api"));
  // 2nd api
  app.use("/cryptocompare", proxy("https://min-api.cryptocompare.com/data"));

  // Note: setupProxy is an express server so you can also override anything in the req or res before proxy them for example 
  app.use("/cryptocompare", (req,res,next) => {
     req.headers = { 
        ...req.headers,
        "my-header":"my header value"
     }
     return proxy("https://min-api.cryptocompare.com/data")(req,res,next);
  });

  app.use("/cryptocompare", proxy("https://min-api.cryptocompare.com/data"));


  // also it's better to use .env variables
  // const {REACT_APP_API_ETHERSCAN_PROXY, REACT_APP_API_ETHERSCAN_BASE_URL} = process.env;
  // app.use(REACT_APP_API_ETHERSCAN_PROXY, REACT_APP_API_ETHERSCAN_BASE_URL);      
};

And for your API it's also better if you can get the base URL from .env variables for example:

const {REACT_APP_API_ETHERSCAN_PROXY, REACT_APP_API_ETHERSCAN_BASE_URL} = process.env;
const baseURL = REACT_APP_API_ETHERSCAN_PROXY || REACT_APP_API_ETHERSCAN_BASE_URL;

Additional advice: instead of keep passing process.env.REACT_APP_API_URL and headers for every API call you may take a look at axios where you can create an API instance with default properties for example:

const {
  REACT_APP_API_ETHERSCAN_PROXY, 
  REACT_APP_API_ETHERSCAN_BASE_URL,
  REACT_APP_API_TIMEOUT,
  REACT_APP_API_ETHERSCAN_KEY
} = process.env;

export const etherscanAPI = axios.create({
  "baseURL": REACT_APP_API_ETHERSCAN_PROXY || REACT_APP_API_ETHERSCAN_BASE_URL,
  "timeout": parseInt(REACT_APP_API_TIMEOUT),
  "headers": {
    "X-Requested-With": "XMLHttpRequest"
  },
  "params": {
    "apiKey": REACT_APP_API_ETHERSCAN_KEY
  }
});

then etherscanAPI.get("/whatever")

Upvotes: 1

roryhewitt
roryhewitt

Reputation: 4507

The fact that you're seeing a 500 response to the preflight OPTIONS request makes me think that perhaps the OPTIONS request method simply isn't allowed by the web server.

Many web servers default to only allowing HEAD, GET and POST, so that would be the first thing I'd check.

If that doesn't help, ensure that the above webpack.config code runs for all requests (i.e. for the OPTIONS and the GET/POST).

If that doesn't help, post a full set of request and response headers to both the OPTIONS and the GET request, and let's see where we go from there.

Upvotes: 1

loveky
loveky

Reputation: 1012

Cannot add comment yet, so I will put it as an answer.

If you are trying to access an API served by another node app or from another host. You can config webpack-dev-server to proxy that request to the real server.

Check the Create React App Doc: Proxying API Requests in Development for more details.

Upvotes: 3

Related Questions