TwitchTV API challenge: inconsistent results on XMLHttpRequest() [SOLVED]

Hello fellow campers,

I have implemented callback functions in native JS (no jQuery, no async/wait) triggered by the result of an API call via XMLHttpRequest().

Note that I am making 2 nested API calls: one to the old TwitchTV API (https://api.twitch.tv/kraken/channels/) and one to the new one (https://api.twitch.tv/kraken/streams/). I am doing these 2 nested calls for 3 TwitchTV channels successively (in a for loop).
The calls are successful and I am able to extract the information I want… except that sometimes only 2, or only 1 or 0 calls are successful.

I have looked for a solution on the forum as well as the Internet, incl. Stack Overflow, but with no success.

I would really appreciate if someone had a clue :slight_smile:

Thanks a mil,

Ed.

Code:
`

// TwitchTV blog https://blog.twitch.tv/client-id-required-for-kraken-api-calls-afbb8e95f843
// call the Twitch API for a channel

    var clientID = "xxxxx";
    var newTwitchTVAPI = "https://api.twitch.tv/kraken/streams/";
    var oldTwitchTVAPI = "https://api.twitch.tv/kraken/channels/";

    var twitchTVurl = "https://www.twitch.tv/"

    var channelArr = [
        "freecodecamp",
        "noobs2ninjas",
        "ESL_SC2"
    ];

    var channelObjArr = [];
    var twitchAPInew = [];
    var twitchAPIv5 = [];

    for (i = 0; i < channelArr.length; i++) {
        // !! important: we need to build a function to localize i
        // otherwise the asynchronous call will callback for the 
        // wrong i value. 
        (function (i) {
            twitchAPIv5.push(new XMLHttpRequest());
            twitchAPIv5[i].open("GET", oldTwitchTVAPI + channelArr[i]);
            twitchAPIv5[i].setRequestHeader("Client-ID", clientID);
            twitchAPIv5[i].send();

            twitchAPInew.push(new XMLHttpRequest());
            twitchAPInew[i].open("GET", newTwitchTVAPI + channelArr[i]);
            twitchAPInew[i].setRequestHeader("Client-ID", clientID);
            twitchAPInew[i].send();

            // build an object for ever channel
            channelObjArr.push(new Object());
            channelObjArr[i].display_name = channelArr[i];
            channelObjArr[i].url = twitchTVurl + channelArr[i];

            // populate that objects with properties from the old API
            twitchAPIv5[i].onreadystatechange = function () {
                if (this.readyState == 4 && this.status == 200) {
                    var temp0 = new Object();
                    temp0 = JSON.parse(this.response);
                    channelObjArr[i].logo = temp0.logo;
                    channelObjArr[i].description = temp0.status;
                }

                twitchAPInew[i].onreadystatechange = function () {
                    if (this.readyState == 4 && this.status == 200) {
                        var temp1 = new Object();
                        temp1 = JSON.parse(this.response);
                        //create a channelObjArr[i] with properties from both twitchAPInew[i] and twitchAPIv5[i]
                        if (temp1.stream == null) {
                            channelObjArr[i].status = "offline";
                        }
                        else {
                            channelObjArr[i].id = temp1.stream._id;
                            channelObjArr[i].status = temp1.stream.stream_type;
                            channelObjArr[i].description = temp1.stream.channel.status;
                            channelObjArr[i].updated_at = temp1.stream.channel.updated_at;
                            channelObjArr[i].video_banner = temp1.stream.channel.video_banner;
                        }
                        console.log(channelObjArr[i]);
                        var htmlCode = "<div class='wrapper'>";
                        htmlCode += "<img class='logo'  src='" + channelObjArr[i].logo + "' alt = 'channel logo' >";
                        htmlCode += "<div class='status' >" + channelObjArr[i].status + "</div>";
                        htmlCode += "<a href='" + channelObjArr[i].url + "'>" + "<div class = 'name-box' >" + channelObjArr[i].display_name + "</div></a>";
                        htmlCode += "<a href='" + channelObjArr[i].url + "'>" + "<div class='description-box'>" + channelObjArr[i].description + "</div></a>";
                        htmlCode += "</div>";

                        var d1 = document.getElementById('total-wrapper');
                        d1.insertAdjacentHTML('beforeend', htmlCode);
                    }
                };
            }
        })(i);
    };
</script>

`

Hey @eduardo,
what’s the reason that some API calls work and some don’t? What kind of error messages are you getting?
There could be a number of reasons for this.

Hi @TomerPacific! Thanks for your message. I really can’t figure why some of the API calls do not work…
The thing is I am not getting any error message at all. The console is empty.

Could it be because while the API calls happen, the value of i changes because of the for loop?

@eduardo,
how about you remove the for loop and try making 3 separate calls and see what you get?

Hi Randell! Right, sorry. You can access it at the codepen here.

@TomerPacific: The for loop is there to loop over the channelArr array, not to make loop over several API calls per se. If I remove this for loop, I will then have to make API/XMLHttpRequest() calls for every TwitchTV channel in the channelArr list. Wouldn’t this be wasteful?

I have also separated the API calls, putting each one in a different array item to avoid any “overlap”.

Is it possible that the 2 TwitchTV APIs are not allowing me to make 33 calls to each in span of a few seconds?

Thanks all :slight_smile:

Hey @eduardo,
I searched online for a bit and found out these two sources :

https://dev.twitch.tv/docs/api

It seems that there is a rate limit for making API calls, but I don’t suspect that you are going over it.

I would try executing calls synchronously, beginning a new one as one completes and seeing what you get.

1 Like

Thanks Tomer. You’re right. I will try to implement the synchronous calls, one at a time to see if I get a different result - and let you know :slight_smile:


UPDATE:
@TomerPacific: I think I may have found the culprit, after searching the TwitchTV Developers pages. The bottleneck was in the old API, which is said to allow only 1 call/sec :
var oldTwitchTVAPI = "https://api.twitch.tv/kraken/channels/"
What I was trying to do until now was to make 30 calls to the old API in a matter of 1-2 seconds. Not good.
After I removed the call to this old API, all my calls to the new API were successful. The new API allows many more calls:

Each client ID is granted a total of 30 queries per minute (if a Bearer token is not provided) or 120 queries per minute (if a Bearer token is provided), across all new Twitch API queries. If this limit is exceeded, an error is returned: HTTP 429 (Too Many Requests).
Source: Twitch API | Twitch Developers

Thanks a lot for your suggestions and your patience! I am grateful ^^

I have finished my project, in case you wanna have a look :
https://user883311.github.io/twitchTV-feed/

Feedback always welcome :slight_smile:

1 Like