Red Cricket
Red Cricket

Reputation: 10470

Trouble understanding axios error handling in react

I am learning about react and django. I have installed django-rest-auth to handle account creations and authentication for users. I also wanted to learn about react and I have install axios to make http request to my django rest api. I want to have a "splash" page where users would first access the site. If the user is already logged in they'll see their profile and other content. If the user isn't logged in they should be presented a login page.

Here's my App.js code I have so far.

import React, { useState, useEffect } from 'react';
import axios from 'axios';

import logo from './logo.svg';
import './App.css';

function LoginPage(props) {

    console.log('LoginPage props are:');
    console.log({ props });

    return (<div className="LoginPage">props are: {props}</div>)
}

function SplashPage(props) {
    const [currentUser, setCurrentUser] = useState(null);

    console.log('SplashPage props are:');
    console.log({ props });

    const userUrl = 'http://localhost:8000/rest-auth/user/';
    console.log('userUrl is:' + userUrl);
    axios.get(userUrl)
        .then(res => { setCurrentUser(res.data); })
        .catch((error) => {
            console.log(error.response);
            return (<div><LoginPage /></div>);
        })
    return (<div className="SplashPage">[{userUrl}] [{currentUser}] </div>);

}


function App() {
    return (
    <div>
      <SplashPage />
    </div>
  );
}

export default App;

Heres my index.js file:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

ReactDOM.render(<App />, document.getElementById('root'));

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: 
serviceWorker.unregister();

When I go to http://localhost:3000 I get this result:

enter image description here

In the developer console looks like

enter image description here

I had hoped to see the content of my LoginPage function.

Upvotes: 0

Views: 139

Answers (1)

Willman.Codes
Willman.Codes

Reputation: 1413

[UPDATED ANSWER]

You are returning <div className="SplashPage">[{userUrl}] [{currentUser}] </div> before <div><LoginPage /></div> because it is outside the axios .then() chain ( ie it called directly after the axios.get() and before any code in the .then() or the .catch() blocks )

Should work:

  • initialize a current user with a loaderState to avoid content flicker
  • Update state within the axios .then() or .catch()
  • Use state to determine what to return from function outside of the promises

-

function SplashPage(props) {
    const [currentUser={notLoaded:true}, setCurrentUser] = useState(null);
    const userUrl = 'http://localhost:8000/rest-auth/user/';
    axios.get(userUrl).then(res => { 
        setCurrentUser(res.data); 
    }).catch((error) => {
        console.log(error)
        setCurrentUser(null)
    })

    //user no authorized
    if(!currentUser)
        return <LoginPage />
    //user authorization unknown
    if(currentUser.notLoaded)
        return <div/>

    //we have a user!
    return <div className="SplashPage">{userUrl} {currentUser}</div>

}

[ORIGINAL ANSWER]

EDIT: sorry I misunderstood your question but will leave my original answer here in case someone comes looking for a related issue.

You are getting a 403 error with the message:

Authentication credentials not provided

You need to add some sort of authorization to your request (consult your django-rest-auth configuration/documentation for how it expects authorization from incoming requests).

You can either set this up for every api call manually or set this up via axios.interceptors.request.use() which you will need to import and call somewhere in your application (such as in your app.js or index.js)

The following example:

  • uses axios.interceptors
  • adds an authorization token to the Authorization header
  • utilizes the standard 'bearer TOKEN'
  • uses firebase auth to demonstrate retrieving token via async

(your actual implementation will depend on how your api is set up and your authorization flow)

addAuthHeader.js:

import axios from 'axios';
import * as firebase from 'firebase/app';

const apiUrl = 'http://localhost:8000/' // '/' if using the preferred http-proxy-middleware

export default addAuthHeader = () => 
    //if firebase auth callback should be asyncasync
    axios.interceptors.request.use(async (config) => {
      if(config.url.startsWith(apiUrl)){
          const token = await firebase.auth().currentUser.getIdToken(true) 
          config.headers.Authorization = `bearer ${token}`;
          return config;
      }
    });

App.js:

addAuthHeader()

Upvotes: 1

Related Questions