Search code examples
reactjspostrequestfetchcross-domain

React app POST issues with CORS and fetch


I have a basic react app communicating with a SQL database and have a demo API running with Flask. I know my API works with manual confirmation on Postman.

I am simply trying to post data to my database via my verified API. However, I run into issues with fetch based on the headers in my post method. Below is my current code:

 const request = new Request("http://155.98.25.80:8000/user", 
        {method: 'POST', 
        headers:{'Content-Type': 'application/json', 'Access-Control-Allow-Origin': "http://localhost:3000/", 
        'Accept':'application/json'}, 
        body: user_data, 
        mode:'cors',
       });
        console.log(request)
        fetch(request)
            .then(response => {
                if (response.status === 200) {
                    return response.json();
                } 
                else {
                    throw new Error('Something went wrong on api server!');
                }
            })
            .then(response => {
                console.debug(response);
                // ...
            }).catch(error => {
                console.error(error);
            });
    } 

It is a pretty standard POST request that is triggered on a button click. When I make this request, I can see the API returns a 200 code, meaning it went through to the database. However, in my browser (Chrome) console, I receive the following error: TypeError: Failed to fetch.

I am pretty lost here. I know my post request is going through, but it seems that the return is failing with the response. I have read many of the other posts dealing with this issue, and I am not sure what is going wrong with my app. Any help would be great.


Solution

  • I ran into this frustrating issue a few years ago and my have an answer for you. Your source of pain is probably the preflight check.

    Why this happens

    When you make a POST request using postman it hits the POST endpoint directly(POST http://155.98.25.80:8000/user)

    But when you make a POST request through Chrome it first goes through a preflight check. This means that it first makes an OPTIONS call to the same endpoint (OPTIONS http://155.98.25.80:8000/user). The OPTIONS call must return what is allowed on that endpoint(for CORS security). The OPTIONS call must return headers that lets Chrome what kinds of requests it accepts and from whom.

    For you, your OPTIONS http://155.98.25.80:8000/user should return

    Access-Control-Allow-Headers: Content-Type, Authorization
    Access-Control-Allow-Methods: POST
    Access-Control-Allow-Origin: *
    

    Note: Access-Control-Allow-Origin should be your specific api URL(maybe 155.98.25.80), * allows everything

    Since Access-Control-Allow-Methods allows POST, POST call will now be allowed when Chrome attempts it.

    How to spot it

    If you open Chrome Dev Tools and go to the Network tab you will see how before it makes a POST call, it makes a OPTIONS call

    enter image description here

    The OPTIONS call returns the Access-Control headers enter image description here

    Then, the POST call can be made enter image description here

    Note

    Chrome does the preflight check on its own, you don't have to add any additional react code to make this happen.

    TL;DR

    Create a new endpoint (OPTIONS http://155.98.25.80:8000/user) in Flask API that returns

    Access-Control-Allow-Headers: Content-Type, Authorization
    Access-Control-Allow-Methods: POST
    Access-Control-Allow-Origin: *