0

I have a MERN application that uses a combination of:

  1. Async/Await with Axios, and
  2. Redux

to manage the data flow throughout my application. Redux is mainly used for login + authorization (along these lines). A few other tables that are shared across many pages on my app are fetched through redux and accessible via reduxState. However, since most of the routes in my MERN app do not require shared state, I simply use axios for the majority of data fetching from my Mongo database.

I am currently having a problem with only the redux fetches, both for login/authorization as well as for all of the other tables fetched through redux. In my console, I am receiving the following errors on redux actions:

enter image description here

enter image description here

The node API for the app is served on port 8080, and if I copy this url, change the port, and paste http://localhost:8080/api/cbb/teams/list directly into my chrome browser, it does return the data as I would expect. So I believe there's an issue with port 3000 / 8080. Port 3000 is where the client side of the application is served (I believe), which I figure is why Redux is doing the GET request to port :3000.

My question is, what can I do to resolve / debug this, so that my Redux fetches work once again? I assume that I simply need to "point" the Redux fetches to the right port, but I'm not sure how to do this.

Edit 1

Along the lines of this question, my client file (with all of my front end code) is inside of the directory for my node API. In my client/package.json file, I have a line with "proxy": "http://localhost:8080",

Edit 2

Here's the main function from teams-action, which builds the URL that is then fetched:

export function fetchTeams(team, conference) {
    return dispatch => {
        let url = '/api/cbb/teams';
        if (team) { url += '/team/' + team; }
        else if (conference) { url += '/conference/' + conference; }
        else { url += '/list'; }

        console.log('fetchTeams url: ', url);
        dispatch(fetchSportsDataBegin());
        return fetch(url)
            .then(handleErrors)
            .then(res => res.json())
            .then(json => {
                dispatch(fetchSportsDataSuccess(json));
                return json;
            })
            .catch(error => dispatch(fetchSportsDataError(error)));
    };
}

fetchCBBTeams is called from my main container component for the page. The url that is printed out is simply /api/cbb/teams/list, since I am intentionally calling it with no parameters

halfer
  • 19,824
  • 17
  • 99
  • 186
Canovice
  • 9,012
  • 22
  • 93
  • 211
  • 1
    Can you show how you are actually making the fetch requests and building up the API URLs? In the first Redux link they are doing `fetch(\`${config.apiUrl}/users/authenticate\`, ...)` and using `config.apiUrl` to configure the API origin. In the second link you posted the OP is failing to use the `proxy` config to make their fetch requests, which is why it's not working for them. – Sly_cardinal Apr 01 '20 at 01:57
  • sure, will make edit to the post - been updated – Canovice Apr 01 '20 at 01:58
  • return fetch(proxy + url) – flakerimi Apr 01 '20 at 02:10
  • When I update the return with `fetch('http://localhost:8080' + url)` then it works, yes – Canovice Apr 01 '20 at 02:16
  • However I don't think I'd want to hardcode this into all of my redux action files, as then it won't fetch from the production path on prod, no? – Canovice Apr 01 '20 at 02:17

2 Answers2

1

This should be your fetch on client

export function fetchTeams(team, conference) {
    return dispatch => {
        let host = "http://localhost:8080";
        let url = '/api/cbb/teams';
        if (team) { url += '/team/' + team; }
        else if (conference) { url += '/conference/' + conference; }
        else { url += '/list'; }

        console.log('fetchTeams url: ', url);
        dispatch(fetchSportsDataBegin());
        return fetch(host + url)
            .then(handleErrors)
            .then(res => res.json())
            .then(json => {
                dispatch(fetchSportsDataSuccess(json));
                return json;
            })
            .catch(error => dispatch(fetchSportsDataError(error)));
    };
}

Notice let host = "http://localhost:8080"; and return fetch(host + url)

Calling just /api/cbb/teams client will get his host. Same as links in html that should start with http like if you make link www.google.com will sent you to domain.com/www.google.com

flakerimi
  • 2,580
  • 3
  • 29
  • 49
  • Won't this only work for my local development version? On production, I'd want the host to be my domain url, not localhost? – Canovice Apr 01 '20 at 02:18
  • 2 other Qs that will help me understand this: (a) is it common practice to always include both the host + url in the fetch inside of a redux action, and (b) this doesn't explain why the proxy was not working for me. – Canovice Apr 01 '20 at 02:19
  • 1
    Well it doesn't work that way, you can define host as global value but it has to be defined somewhere or it will use client host. – flakerimi Apr 01 '20 at 02:23
  • 1
    One more thing about Q(b) : Keep in mind that proxy only has effect in development (with npm start), and it is up to you to ensure that URLs like /api/todos point to the right thing in production." https://create-react-app.dev/docs/proxying-api-requests-in-development/ – flakerimi Apr 01 '20 at 02:38
  • 1
    I've updated my answer showing how to use environment variables, as mentioned in the documentation link in flakerimi's comment – Sly_cardinal Apr 01 '20 at 02:39
1

You're running into the same issue as your linked question and the same answer will fix the problem.

If you're using the package.json proxy property to configure the API origin then you'll need to find some way of getting that value into your application code and using it to configure the fetch URLs you are generating.

As an example, at the bottom of the "React Hooks + Redux - User Registration and Login Tutorial & Example" article you have linked, in the React Webpack Config section it shows how they are configuring the config.apiUrl value so it can be used in their application.


New example using .env file to configure API url

You can use a .env file with create-react-app to configure this sort of value for your application.

The benefit of this is that it's a standard and well-understood pattern and it allows easy configuration of development and production variables like this.

Create a .env file in the root of your project to configure the API origin for production:

    # .env
    REACT_APP_PROXY=http://my-production-domain-and-port:8080

Then create a .env.development file to configure the API origin for your local development:

    # .env.development
    REACT_APP_PROXY=http://localhost:8080

create-react-app should automatically load this file and it's variables into your application (see the docs for details).

Then you can access this environment variable inside your application:

    // config.js
    // You can collect together any other environment variables here as well
    const apiUrl = process.env.REACT_APP_PROXY;

    export default {
        apiUrl
    }
    import config from './path-to/config';

    export function fetchTeams(team, conference) {
        return dispatch => {
            let url = `${config.apiUrl}/api/cbb/teams`;
            if (team) { url += '/team/' + team; }
            else if (conference) { url += '/conference/' + conference; }
            else { url += '/list'; }

            console.log('fetchTeams url: ', url);
            dispatch(fetchSportsDataBegin());
            return fetch(url)
                .then(handleErrors)
                .then(res => res.json())
                .then(json => {
                    dispatch(fetchSportsDataSuccess(json));
                    return json;
                })
                .catch(error => dispatch(fetchSportsDataError(error)));
        };
    }
Sly_cardinal
  • 12,270
  • 5
  • 49
  • 50
  • i'm not quite sure if i've ever made an edit to a `webpack.config.js` file. I created this app ~18 months ago using create-react-app, and all of the webpack stuff has been mostly abstracted away from me. – Canovice Apr 01 '20 at 02:24
  • I may already have a .env file somewhere, as I've used process.env.NODE_ENV previously. However I am struggling to find when I set NODE_ENV - edit: nvm looks like NODE_ENV is a default environment variable. – Canovice Apr 01 '20 at 02:53
  • This was all super helpful. Thank you – Canovice Apr 01 '20 at 03:02