Utilizing Javascript to make multiple API requests to fetch data from Youtube

Currently, I am attempting to create a JSON object that represents the views per video for a specific YouTube user.

To achieve this, I start by making an API call to retrieve all the video IDs from a designated channel, storing them in an empty array. Subsequently, I iterate through each video ID to make multiple API calls for individual videos in order to collect data about their respective views.

At present, each video requires its own API call and I am facing challenges in consolidating all the data retrieved from these calls into a single object.

I recognize that there might be a more efficient approach to address this issue, and I am seeking recommendations on how to better handle this situation.

Thank you!

var channelId = 'UCO1cgjhGzsSYb1rsB4bFe4Q'
var url = 'https://www.googleapis.com/youtube/v3/search?key=' + apiKey + '&channelId=' + channelId + '&part=snippet,id&order=date&maxResults=20'

fetch(url).then((resp) => resp.json()).then(function(data) {
        var videoIds = []
        for (var i = 0; i < data.items.length; i++) {
            videoIds.push(data.items[i].id.videoId)
        }
        return videoIds
    }).then(function(ids) {
        var urls = []
        for (var i = 0; i < ids.length; i++) {
            urls.push('https://www.googleapis.com/youtube/v3/videos?part=statistics&id=' + ids[i] + '&key=' + apiKey)
        }
        return urls
    }).then(function(urls) {
            for (var i = 0; i < urls.length; i++) {
                fetch(urls[i]).then((resp) => resp.json()).then(function(data) {
                    console.log(data)
                })
            }

update

I found a solution to this problem by utilizing another fetch URL along with the d3.json function.

var search = 'https://www.googleapis.com/youtube/v3/search?key=' + apiKey + '&channelId=' + channelId + '&part=snippet,id&order=date&maxResults=5'

var videoIds = []

fetch(search).then((resp) => resp.json())
.then(function(data) {
    for (var i = 0; i < data.items.length; i++) {
        videoIds.push(data.items[i].id.videoId)
    }

    return fetch("https://www.googleapis.com/youtube/v3/videos?id=" +videoIds + "&part=snippet%2CcontentDetails%2Cstatistics&key=" + apiKey);

}).then(function(response) {
        d3.json(response.url, function(error, data) {
                    if (error) throw error;
                    console.log(data)

Answer №1

To ensure all parallel promises return successfully before proceeding, you have the option to create a custom promise as a wrapper that waits for their completion. If all promises are successful, you can use resolve to confirm success or reject to handle errors.

The crucial part of this process occurs within the function

getChannelVideos(channelId, config)
, specifically inside the Promise body:

var channelId = 'UCO1cgjhGzsSYb1rsB4bFe4Q'

 + '&channelId='
const baseUrl = 'https://www.googleapis.com/youtube/v3';
let config = {
  apiKey: 'yourKeyHere',
  part: 'snippet,id',
  order: 'date',
  maxResults: 20
}

function queryArgs(config) {
  let query = '';
  config.apiKey ? query += '?key=' + config.apiKey : throw { err: 'You must provided an API KEY' };
  config.part ? query += '&part=' + config.part : query;
  config.order ? query += '&order=' + config.order : query;
  config.maxResults ? query += '&maxResults=' + config.maxResults : query;
  return query;
}

function getChannelVideos(channelId, config) {
 let URL = baseUrl + '/search' + queryArgs(config) + '&channelId=' + channelId;
 // Wrap necessary actions in a Custom Promise and return it for handling
  return new Promise((resolve, reject) => {
    // variables to store video data and promises to wait on
    let videos = [];
    let videoPromises = [];
    // Execute Channel Request followed by video requests (Callback hell)
    fetch(URL)
      .then((resp) => resp.json())
      .then(
        data => {
            // Declare vars outside map for improved memory management
            let currentVideoId;
            let currentRequestUrl;
            // Iterate over 'data.items' creating an array of promises using .map(handler)
            videoPromises = data.items.map(item => {
              currentVideoId = item.id.videoId;
              currentRequestUrl = baseUrl + '/videos?part=statistics&id=' + currentVideoId + '&key=' + config.apiKey;
              return fetch(currentRequest)
                       .then(
                         res => {
                           // Store Video Response in videos array
                           videos.push(res);
                         }, 
                         err => {
                           console.log('A Video request failed', err);
                         });
            });
        });
      
      // Wait for ALL promises to succeed
      Promise.all(videoPromises).then(
        success => {
          console.log('All retrieved successfully!');
          resolve({
            status: 200,
            data: {
              videos : videos
            }
          });
        },
        err => {
          reject({ 
            status: 500,
            error: err, 
            message: 'Something went wrong, but the data is available!', 
            data: videos 
          });
        })
  });
}

// CALL THE FUNCTION
getChannelVideos(channelId, config).then(
  res => {
    // Access the retrieved videos
    console.log('videos[]', res.data.videos);
  },
  err => {
    console.log('Error occurred', err);
  });

This approach should enhance performance with fewer loops and reduced call stack. Utilizing Array.map(handler) is recommended by the JavaScript community for its efficiency. Happy Coding!

Answer №2

To eliminate the Promise chaos come on in

ES2017 async/await structure

Revamp your entire code to resemble something like this

async function bar() {
    var userId = 'UCO1cgjhGzsSYb1rsB4bFe4Q'
    var link = `https://www.googleapis.com/youtube/v3/search?key=${apiKey}&channelId=${userId}&part=snippet,id&order=date&maxResults=20`

    var response = await fetch(link)
    var info = await response.json()

    var videoIds = []
    for (var item of info.items)
        videoIds.push(item.id.videoId);

    var linksArr = []
    for (var id of videoIds)
        linksArr.push(`https://www.googleapis.com/youtube/v3/videos?part=statistics&id=${id}&key=${apiKey}`);

    for (var currentUrl of linksArr) { //This loop will pause at each URL to complete its fetch
        let response = await fetch(currentUrl)
        let info = await response.json()
        console.log(info)
    }
    return 'Well done Anakin, well done'
} 

bar()
.then(message => console.log(message))
.catch(error => console.log(error)) //If an error has been thrown or a fetch was rejected.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

An error occurred while attempting to save a new entry using the New Entry Form in DataTable, stating that the variable "

I have encountered an issue with a table that includes a bootstrap modal containing a form. After filling out the form and saving the data or closing the modal, I want to refresh the table data. However, I am receiving the following error: TypeError: c i ...

The SetInterval notifications remain stagnant without any alterations

I am currently working on designing a loading screen for a game using HTML and JavaScript. My goal is to have different messages displayed every three seconds. Despite using the setInterval function successfully for other tasks (like triggering an alert ...

Tips on transferring information from a component to an instance in Vue

My goal is to retrieve data from a component and transfer it to a variable within my root Vue instance. Vue Instance Configuration: new Vue({ el: '#root', data: { searchResultObject: '' }, methods: { // ...

What is the best way to deserialize a JSON document from std::map in C++ using Delphi?

I received a JSON string from C++ which looks like this: "{"name":"mark","data":[1,2,3,4],"some":"11.1":"Hello","22.2":",&","44.4":"World"}}" Unfortunately, when trying to deserialize this JSON string using mormot in Delphi, it failed as I lacked an appr ...

Executing React's useEffect inside a loop will result in only the last effect being triggered

My application features a collection of checkboxes with an option to select or deselect all at the top. I manage the selected checkboxes in a state array, and when a checkbox is toggled, a useEffect() function is triggered to place markers on a Leaflet map ...

Manage and update events in the Angular Bootstrap Calendar

For the past few days, I have been working on integrating a calendar into my project. I decided to repurpose an example provided by the developer. One issue that I've come across is related to the functionality of deleting events when using the dropdo ...

Is the Sourcecode for the Raspberry Pi Cam with WebRTC and UV4l driver Closed?

I'm utilizing the UV4L driver (RasPiCam) from this link along with the WebRTC extension to achieve a continuous live view, streaming out via this HTTP server (RaspberryPi). I am interested in examining the source code being executed on the server. Is ...

Troubleshooting: JavaScript Object isn't appending to array

(Just so you know, I really appreciate your help as I navigate through teaching myself). I'm currently working on recreating an array that was previously parsed from session storage. var entries = JSON.parse(sessionStorage.getItem('entries&apo ...

How to Transfer Data from SuperAgent Library Outside the .then() Block?

I have a dilemma in my Nodejs project with two interdependent files. The key to this issue lies in the usage of a crucial library known as SuperAgent (I need it) Check out SuperAgent Library Here In file1.js const file2 = require('./file2'); ...

Encountering a "Can't find variable" error in Java when using Ghostdriver 1.2.1 with PhantomJS 2.0 and the newest version

[ALERT - 2016-01-16T02:22:00.898Z] Session [e6651a90-bbf7-11e5-9061-cff578894101] - page.onError - msg: ReferenceError: Can't find variable: data :262 in error [WARNING - 2016-01-16T02:22:00.898Z] Session [e6651a90-bbf7-11e5-9061-cff578894101] ...

The swap feature in drag-and-drop does not have a defined function

I am currently developing a to-do app that utilizes drag and drop functionality to reorder items in the list. However, I have encountered an issue where swapping elements works perfectly for the first five elements but throws errors when dealing with the s ...

Adding a new row to a table is causing issues with jQuery

var info = [{ "pin": "015-08-0011-000-01", "arp": "015-08-0011-000-01", "tin": "342-432-423-000", "firstname": "John", "middlename": "James", "lastname": "Jones", "suffix": "", "qtr": "1st ...

The parameter in a JavaScript for loop

I'm struggling with my Javascript skills. Here is the code snippet I am currently working with: var information = [ {"Column":"","keyw":"","Column_3":"day of march 2011 to someother numeric" ...

Using VueJS to perform a filtering operation on the JSON data when a button is clicked

I need to implement a filter function for my fetched json data using buttons. When a button is clicked, only the data (in this case book names) that match the clicked button should be displayed while hiding the others until another button is clicked. The ...

the transparency feature in three.js is completely malfunctioning

I've been browsing through some questions that have already been asked by others here, and one that caught my attention is: Transparent background with three.js I am struggling to make the background transparent instead of black as described in the ...

What is the best way to send a JSON object in Vue.js?

<template> <div id="app"> <div id="bee-plugin-container"></div> </div> </template> <script> // import axios from "axios"; // import Bee from "@mailupinc/bee-plugin"; import $ from 'jquery' ...

Updating HTML content using jQuery by iterating through an array

When I write the following HTML code: <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> <h1 id="message"> </h1> and include the corresponding JavaScript code: messages = ["Here", "are", ...

Activate the front camera on an Android device using HTML5 or JavaScript

I'm currently working on a web app that needs to access the front camera of Android phones running version 4.0 or higher. After taking a picture, the app should then upload the captured image to my own server. Is there a way to launch the front camer ...

Managing the verification of data existence in the ExpressJS service layer or controller

Working on a medium-sized website, I realized the importance of writing maintainable code with a better project structure. After stumbling upon this insightful article and some others discussing the benefits of 3-layer architecture, I found the concept qu ...

Can you come up with a catchy one-liner for an array that contains all the elements of the arrays that came

I am currently working with the array [1,2,3,4,5,6,7,8,9] My goal is to achieve [ [1], [1,2], [1,2,3], [1,2,3,4], [1,2,3,4,5], ... ] I envision the desired outcome as const var = array.reduce **using some form of black magic** I ...