reactjscorsphoenix-frameworkfetch-apiisomorphic-fetch-api

Not getting data back from isomorphic-fetch (React/Phoenix)


I have a create-react-app on localhost:3000 and a phoenix 1.3 server on :4000. I am trying to set up JWT authentication between the two.

When I curl my server it works fine.

$ curl -H "Content-Type: application/json" -X POST -d '{"session":{"email":"me@example.com", "password":"password"}}' http://localhost:4000/api/v1/sessions

>>> {"user":{"id":1,"handle":"me","email":"me@example.com"},"jwt":"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJVc2VyOjEiLCJleHAiOjE1MDYxNzQ2MzcsImlhdCI6MTUwMzU4MjYzNywiaXNzIjoiQXRoZW5hIiwianRpIjoiY2I5YjgyMDMtZjMxMi00YTE2LWIwOTItZjg4NDVlNmUzYzhiIiwicGVtIjp7fSwic3ViIjoiVXNlcjoxIiwidHlwIjoidG9rZW4ifQ.mg36_4Nj2tf26ey7c72rHnZKhQBlQZeBt1CSnsua44YYndt3i9ltPA1oq_WTp58f0f6X2KqioPlrdns2O5drgQ"}

The React side looks like this:

import React        from 'react';
import fetch        from 'isomorphic-fetch';
import { polyfill } from 'es6-promise';

const defaultHeaders = {
  Accept: 'application/json',
  'Content-Type': 'application/json',
};

function headers() {
  return { ...defaultHeaders };
}

...
fetch("http://localhost:4000/api/v1/sessions", {
   method: 'post',
  headers: headers(),
  body: JSON.stringify({session: {email: "me@example.com", password:"password"}}),
}).then(function(response){
  console.log(response);
  alert("Pausing so browser does not refresh");
})

When I make the fetch call, the server console outputs as though a curl request came in successfully. However, nothing seems to happen in any function I put in fetch's first .then() clause. I do not see an alert or a console.log(response).

Initially I thought this was a CORS issue, but I installed cors_plug in phoenix and see the desired behavior on the server. I also installed the Allow-Control-Allow-Origin plugin on Chrome.

Is there something I am missing about isomorphic-fetch? (Or, alternatively, is there a more 'React' way to do this?)


Solution

  • The Content-Type: application/json header added by the code in the question triggers the browser to do a CORS preflight OPTIONS request. So to emulate that in curl you need to do:

    curl -X OPTIONS -i -H 'Origin: http://localhost:3000' \
       -H 'Access-Control-Request-Method: POST' \
       -H 'Access-Control-Request-Headers: Content-Type' \
       http://localhost:4000/api/v1/sessions
    

    A comment above indicates the server responds to that with 204, which shows the server’s at least configured to handle OPTIONS requests, so that part’s fine. But what’s not fine: the same comment indicates one response the server sends back to the browser is a 400 (“bad request”), meaning the request the server received from the browser wasn’t what the server expected.

    So you can open the Network pane in your browser devtools, reload and examine the details of the POST request the browser sent—ensure it’s actually sent the Content-Type: application/json request header and the body of the request looks like what you’re sending with curl.