0

When I send a GET request from my ReactJS frontend, It recieves an error even though my django backend shows [10/Mar/2018 23:31:08] "GET /post/ HTTP/1.1" 200 930 in the terminal.

I'm using redux sagas.

src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import { BrowserRouter, Route, Switch, Redirect } from 'react-router-dom';
import createSagaMiddleware from 'redux-saga'
import rootSaga from './sagas'
import rootReducer from './reducers';
import PostsIndex from './components';

const sagaMiddleware = createSagaMiddleware();
const store = createStore(
  rootReducer,
  applyMiddleware(sagaMiddleware)
);
sagaMiddleware.run(rootSaga);

ReactDOM.render(
  <Provider store={store}>
    <BrowserRouter>
      <div>
        <Switch>
          <Route path="/" component={PostsIndex}/>
        </Switch>
      </div>
    </BrowserRouter>
  </Provider>
  , document.querySelector('.container'));

src/components/index.js

import React, { Component } from 'react';
import { fetchPosts } from '../actions';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import _ from 'lodash';


class PostsIndex extends Component {
  componentDidMount() {
    this.props.fetchPosts();
  }

  renderPosts() {
    return _.map(this.props.posts, (post) => {
      return(
        <li className="list-group-item" key={post.id}>
          {post.text}
        </li>
      )
    })
  }

  render() {
    const { posts } = this.props
    if (posts.isLoading) {
      return (
          <div>
            <h3>Loading...</h3>
          </div>
      )
    } else if (posts.error) {
      return (
        <div>
          <h3>Error getting posts</h3>
          <h2>{JSON.stringify(posts.error)}</h2>
        </div>
      )
    } else {
      return (
        <div>
          <div className="text-xs-right">
            <Link className="btn btn-primary" to="/posts/new">
              Add a Post
            </Link>
          </div>
          <h3>Posts</h3>
          <ul className="list-group">
            {this.renderPosts()}
          </ul>
        </div>
      );
    }
  }
}

function mapStateToProps({ posts }){
  return { posts }
}

export default connect(mapStateToProps, { fetchPosts })(PostsIndex);

src/actions/index.js

export const FETCH_POSTS = 'fetch_posts';

export function fetchPosts() {
  return { type: FETCH_POSTS };
}

src/api/index.js

import axios from 'axios';
const ROOT_URL = 'http://127.0.0.1:8000';

export function fetch(endpoint) {
  return axios.get(`${ROOT_URL}/${endpoint}/`)
            .then(response => ({ response }))
            .catch(error => ({ error }));
}

src/reducers/index.js

import { combineReducers } from 'redux';
import { POSTS_REQUESTED, POSTS_RECEIVED, POSTS_REQUEST_FAILED } from '../sagas';
import _ from 'lodash';

function postsReducer(state = {}, action) {
  switch(action.type) {
    case POSTS_REQUESTED:
        return {
            content: null,
            isLoading: true,
            error: null
        }
    case POSTS_RECEIVED:
      return {
          content: _.mapKeys(action.posts, 'id'),
          isLoading: false,
          error: null
      }
    case POSTS_REQUEST_FAILED:
      return {
          content: null,
          isLoading: false,
          error: action.error
      }
    default:
      return state;
  }
}

const rootReducer = combineReducers({
  posts: postsReducer,
});

export default rootReducer;

src/sagas/index.js

import { call, put, takeEvery } from 'redux-saga/effects'
import { fetch } from '../api';
import { FETCH_POSTS } from '../actions';

export const POSTS_REQUESTED = 'posts_requested';
export const POSTS_RECEIVED = 'posts_recieved';
export const POSTS_REQUEST_FAILED = 'posts_request_failed';

export function* fetchPosts() {
  yield put({ type: POSTS_REQUESTED })
  const { response, error} = yield call(fetch, 'post');
  if (response)
    yield put({ type: POSTS_RECEIVED, posts: response })
  else
    yield put({ type: POSTS_REQUEST_FAILED, error })
}

export function* watchFetchPosts() {
  yield takeEvery(FETCH_POSTS, fetchPosts);
}

// single entry point to start all Sagas at once
export default function* rootSaga() {
  yield [
    watchFetchPosts()
  ]
}

The output I get is

Error getting posts {"config":{"transformRequest":{},"transformResponse":{},"timeout":0,"xsrfCookieName":"XSRF-TOKEN","xsrfHeaderName":"X-XSRF-TOKEN","maxContentLength":-1,"headers":{"Accept":"application/json, text/plain, /"},"method":"get","url":"http://127.0.0.1:8000/post/"},"request":{}}

When I copy paste that url into my browser, it works perfectly, so it has to be a problem with the frontend.

Why am I getting this error?

Matt
  • 2,232
  • 8
  • 35
  • 64
  • I think using JSON.stringify on the error might be removing some useful information. What do you get when you read posts.error.message? (Also this might be useful: https://github.com/axios/axios#handling-errors ) – Martin Kadlec Mar 11 '18 at 00:51
  • @MartinKadlec When I do that, it says Network Error – Matt Mar 11 '18 at 01:05
  • @MartinKadlec also, I looked at that documentation. `error` has no response member and it's request member is empty, so it's not really helpful. – Matt Mar 11 '18 at 01:08
  • And what does network tab say? – bigless Mar 11 '18 at 02:48
  • @bigless It shows the /post/ request and says 200. There are four other things in there which I've not sure are relevant. `GET http://localhost:3000/` returned 304, `GET http://localhost:3000/static/js/bundle.js` returned 304, `GET http://localhost:3000/sockjs-node/info?t=1520736729536` returned 200 and `GET http://localhost:3000/sockjs-node/425/ljoxvei4/websocket` returned 101 – Matt Mar 11 '18 at 02:56
  • Look at this https://github.com/facebook/react-native/issues/934#issuecomment-150772039. Reactjs could be almost same. Then you will be able to better debug responses.. – bigless Mar 11 '18 at 03:17
  • I would try to replace axios with native xmlhttlrequest and then debug the onreadystatechange event. It might give you some hint axios is hiding from you. – Martin Kadlec Mar 11 '18 at 11:35

1 Answers1

0

Turns out the problem was related to this

Since I'm using django-rest, I just had to add django-core-headers to my backend like in this answer

Matt
  • 2,232
  • 8
  • 35
  • 64