2
votes

I'm trying to get data from an API using Axios. I have two API calls. The first call runs fine, and I get the data I expect. The second one, however, comes back with the 400 error bad request.

I've searched through multiple forums to try and find a solution, but I don't quite understand the code that I find.

    const [player, setPlayer] = useState([]);
    const [newPlayer, setNewPlayer] = useState([]);

    const FindLoadout = async () => {
        await axios.get(`http://api.paladins.com/paladinsapi.svc/getmatchidsbyqueueJson/${devId}/${generateSignature('getmatchidsbyqueue')}/${props.sess}/${moment.utc().format('YYYYMMDDHHmmss')}/428/${moment.utc().format('YYYYMMDD')}/-1,00`).then((response) => {
                const playerData = response.data;
                playerData.map((el) => {
                    player.push(el.Match)
                })
                console.log(player);
                for(let i = 0; i < 50; i++) {
                    newPlayer.push(player[i]);
                }
                console.log(newPlayer);
            }).catch((error) => {
                console.log(error);
            });
            axios.get(`http://api.paladins.com/paladinsapi.svc/getmatchdetailsbatchJson/${devId}/${generateSignature('getmatchdetailsbatch')}/${props.sess}/${moment.utc().format('YYYYMMDDHHmmss')}/${newPlayer.join(",")}`).then((response) => {
                console.log(response);
            }).catch((error) => {
                console.log(error);
            });
    }

The error message is:

Error: Request failed with status code 400 at createError (createError.js:17) at settle (settle.js:19) at XMLHttpRequest.handleLoad (xhr.js:60)

3
Code sample is incomplete: player and newPlayer aren't defined.Brandon Hill
Edited, thank you.CodyLee
Not sure if it's the only issue here, since this is pretty API-specific and you've not included code for generateSignature etc., but you're not using the useState hook correctly. The second value it returns is how it's supposed to be updated, like: setPlayer(myUpdatedValue): reactjs.org/docs/hooks-state.htmlBrandon Hill

3 Answers

2
votes

I don't know if it will exactly address your problem, but when using async / await for data fetching, a common practice is to do it more like this :

const FindLoadout = async () => {

  const playerData= await axios
    .get(`http://api.paladins.com/player/154`)
    .then(response => response.data);

  const gameData= await axios
    .get(`http://api.paladins.com/game/788`)
    .then(response => response.data);

  return {player: playerData, game: gamedata}
}

That is to say, you assign the data fetched by your API calls to variables, and then return the data that you need from them (after whatever manipulation you deem necessary).

The ability to write asynchronous code in that kind of synchronous syntax is one of the most appealing trait of async / await.

I suspect the errors you get are because you second call does not have the await keyword before it is fired.

EDIT : also, as other have remarked, you are definitely going to encounter issues with your incorrect use of hooks, but this is not the scope of the question.

0
votes

Firstly you are mixing async and traditional promises

[EDIT: you are also mutating state directly instead of using setState]

[EDIT2: setting state is not immediate therefor a console.log of state (and the axios get request relying on the state value) directly after a setState will not usually log the value you anticipate and therefore should be included inside the callback function passed to setState -or- utilize useEffect when the state does update]

[EDIT3: build new state outside of loop then setState after]

const [player, setPlayer] = useState([]);
const [newPlayer, setNewPlayer] = useState([]);
const FindLoadout = async () => {
    useEffect(()=>{
        if (!player.length) return
        const newState = [...newPlayer]
        for(let i = 0; i < 50; i++) {
            newState.push(player[i]);
        }
        setNewPlayer(newState)
    }, [player]);
    useEffect(() => {
        if (!newPlayer.length) return 
         axios
            .get(`http://api.paladins.com/paladinsapi.svc/getmatchdetailsbatchJson/${devId}/${generateSignature('getmatchdetailsbatch')}/${props.sess}/${moment.utc().format('YYYYMMDDHHmmss')}/${newPlayer.join(",")}`)
            .then((gameData)=>{
                console.log(gameData)
            }).catch((error)=>{
                console.error(error)
            })
    }, [newPlayer]);
    try {
        const playerData= await axios.get(`http://api.paladins.com/paladinsapi.svc/getmatchidsbyqueueJson/${devId}/${generateSignature('getmatchidsbyqueue')}/${props.sess}/${moment.utc().format('YYYYMMDDHHmmss')}/428/${moment.utc().format('YYYYMMDD')}/-1,00`)
        const newState = [...player]
        playerData.map((el) => newState.push(el.Match))
        setPlayer(newState)
    }catch(error) {
        console.error(error);
    } 
}

If you want to stick with asyc for the second useEffect you can also use a callback instead: https://dev.to/n1ru4l/homebrew-react-hooks-useasynceffect-or-how-to-handle-async-operations-with-useeffect-1fa8

useEffect(() => {
        if (!newPlayer.length) return
        const myCallback = async ()=>{
            try{
                const gameData = await axios.get(`http://api.paladins.com/paladinsapi.svc/getmatchdetailsbatchJson/${devId}/${generateSignature('getmatchdetailsbatch')}/${props.sess}/${moment.utc().format('YYYYMMDDHHmmss')}/${newPlayer.join(",")}`)
                console.log(gameData)
            }catch(error){
                console.error(error)
            }
        }
        myCallback()
}, [newPlayer]);

If that doesn't fix the issue:

The 400 Bad Request error is an HTTP status code that means that the request you sent to the website server was somehow incorrect or corrupted and the server couldn't understand it.

ie: Your URL is incorrect for the API call I would double check that the "generateSignature" function is returning the proper value. If that is the case I would check to make sure that newPlayer.join(",") is returning the proper value.

0
votes

I believe the problem is with how you are assigning values to player and newPlayer. Since you are using the useState hook you are supposed to use setPlayer and setNewPlayer.

Could you tell me what's the value of newPlayer before the second api call?

Maybe you could update it like this:

const FindLoadout = async () => {
        await axios.get(`http://api.paladins.com/paladinsapi.svc/getmatchidsbyqueueJson/${devId}/${generateSignature('getmatchidsbyqueue')}/${props.sess}/${moment.utc().format('YYYYMMDDHHmmss')}/428/${moment.utc().format('YYYYMMDD')}/-1,00`).then((response) => {
                const playerData = response.data;
                //playerData.map((el) => {
                //    player.push(el.Match)
                //})
                setPlayer(playerData.map(el) => el.Match);
                console.log(player);
                //for(let i = 0; i < 50; i++) {
                //    newPlayer.push(player[i]);
                //}
                // I'm not sure how to update this assignment
                console.log(newPlayer);
            }).catch((error) => {
                console.log(error);
            });
            axios.get(`http://api.paladins.com/paladinsapi.svc/getmatchdetailsbatchJson/${devId}/${generateSignature('getmatchdetailsbatch')}/${props.sess}/${moment.utc().format('YYYYMMDDHHmmss')}/${newPlayer.join(",")}`).then((response) => {
                console.log(response);
            }).catch((error) => {
                console.log(error);
            });
    }

About updating newPlayer: since states are updated asynchronously, by the time you try to update newPlayer using the values in player, player has nothing in it.

Try to make the request with some hardcoded values to see if the problem is with the api requests or with the values in your variables.