Twitch API Feedback

So I took a huge break from FCC, but am back at it this week!

I spent a few hours setting up the logic for the Twitch viewer and would like some critique of my code so far

https://github.com/ddeason37/FC-TwitchViewer.git

const $main = $('#main'),
			$title = $('#title'),
			$fcStatus = $('#FC-status'),
			$status = $('#status'),
			$streamers = $('#streamers');

const streamersArr = ["ESL_SC2", "OgamingSC2", "cretetion", "freecodecamp", "storbeck", "habathcx", "RobotCaleb", "noobs2ninjas"];

$(function(){
	isCodeCampOnline();

	streamersArr.forEach(function(e,i){
		getTwitchUserInfo(e);
	});

		//Make call to api
	function isCodeCampOnline() {
		$.ajax({
			url: 'https://wind-bow.gomix.me/twitch-api/streams/freecodecamp',
			type: 'GET',
			dataType: 'jsonp',
			success: function(data){
				console.log(data.stream);
				if(data.stream == null) {
					$fcStatus.append('<h3>FC is OFFLINE<h3>');
				} else {
					$fcStatus.append('<h3>FC is ONLINE! <a href="https://api.twitch.tv/kraken/channels/freecodecamp">View Channel</a></h3>')
				}
			}
		});
	}//End isCodeCampOnline()

	function getTwitchUserInfo(user) {
		$.ajax({
			url: 'https://wind-bow.gomix.me/twitch-api/users/' +user,
			type: 'GET',
			dataType: 'jsonp',
			async: false,
			success: function(data){
				let logo = data.logo,
							name = data.display_name,
							bio = data.bio;

				isUserOnline(user, data.logo, data.display_name, data.bio);
			}
		})
	}//End getTwichUserInfo()

	function isUserOnline(user, logo, name, bio) {
		$.ajax({
			url: 'https://wind-bow.gomix.me/twitch-api/streams/' +user,
			type: 'GET',
			dataType: 'jsonp',
			success: function(statusData){

				//In case no BIO info given
				if(bio == null) {
					bio = '<p>No BIO given, this guy must be a ninja</p>';
				}

				let status;

				if(statusData.stream == null) {
					status = '<p> is OFFLINE<p>';
				} else {
					status =  '<p> is ONLINE! <a target="_blank" href="https://www.twitch.tv/'+user+'">View Channel</a><p>';
				}

				var html = 	'<div class="user-div">'+
							'<div class="logo"><img src="' +logo+ '"</div>'+
							'<div class="name">' +name+ '</div>'+
							'<div class="user-status">' +status+ '</div>'+
							'<div class="info"><h3 class="user-bio">' +bio+ '</h3></div>'+
							'</div>';
				
				console.log(status);
				$status.append(html);
			}
		})
	}//End isUserOnline()
})//End jQuery

It’s far from done, but seems to working as planned so far

Thanks!

Not bad. It seems like you’ve got a handle on this AJAX thing, so you may want to try working with promises instead of callbacks. Of course, you don’t have to, but promises are a big deal and this is a good project to try them out with.

jQuery AJAX functions all return promise-like objects, so it’s easy to use. They won’t make any sense immediately, but once you “get it”, your code will be much, much cleaner and easier to read.

$.getJSON(url)
  .then(function(data) {
      //do stuff with data
      return $.getJSON(otherUrl)
    })
    .then(function(otherData) {
      //do stuff with data from otherUrl
    })
    .catch(function(error) {
      //something bad happened
    })

Thanks for the input, will give this a shot!

So I did some reading this morning, and while I really need to do a lot more research on promises, I’ve refactored my code and moved away from using callbacks

const $main = $('#main'),
			$title = $('#title'),
			$fcStatus = $('#FC-status'),
			$status = $('#status'),
			$streamers = $('#streamers');

const streamersArr = ["ESL_SC2", "OgamingSC2", "cretetion", "freecodecamp", "storbeck", "habathcx", "RobotCaleb", "noobs2ninjas"];

$(function(){
	
	//Is FreeCodeCamp online?
	$.getJSON('https://wind-bow.gomix.me/twitch-api/streams/freecodecamp?callback=?')
	  .then(function(data){
			//console.log(data.stream);
			if(data.stream == null) {
				$fcStatus.append('<h3>FC is OFFLINE<h3>');
			} else {
				$fcStatus.append('<h3>FC is ONLINE! <a href="https://api.twitch.tv/kraken/channels/freecodecamp">View Channel</a></h3>');
			}
		})

	//Loop throught streamers array and append data
	streamersArr.forEach(function(e,i){
		getTwitchUserInfo(e);
	});


	function getTwitchUserInfo(user) {
		//Create user object outside of promises scope 
		//so we can access throughout the chain
		let userInfo = {
			logo: '',
			name: '',
			bio: '',
			status: ''
		}

		$.getJSON('https://wind-bow.gomix.me/twitch-api/users/' +user+ '?callback=?')
		  .then(function(data){
		  	//console.log(data);

		  	//Assign data to userInfo object
		  	userInfo.logo = data.logo;
		  	userInfo.name = user;
		  	userInfo.bio = data.bio;
		  	
				//In case no BIO info given
				if(user.bio == null) {
					data.bio = '<p>No BIO given, this guy must be a ninja</p>';
				}

				return $.getJSON('https://wind-bow.gomix.me/twitch-api/streams/' +user+ '?callback=?');
			})
			.then(function(userStatus) {
				console.log(userInfo);

				//Check to see if user is online
				if(userStatus.stream == null) {
					userInfo.status = '<p> is OFFLINE<p>';
				} else {
					userInfo.status =  '<p> is ONLINE! <a target="_blank" href="https://www.twitch.tv/'+user+'">View Channel</a><p>';
				}

		    var html = 	'<div class="user-div">'+
										'<div class="logo"><img src="' +userInfo.logo+ '"</div>'+
										'<div class="name">' +userInfo.name+ '</div>'+
										'<div class="user-status">' +userInfo.status+ '</div>'+
										'<div class="info"><h3 class="user-bio">' +userInfo.bio+ '</h3></div>'+
										'</div>';

				$status.append(html);
			})
	}//End getTwichUserInfo()
})//End jQuery

Seems to be working just fine, I very much appreciate the input!

Are promises meant to just reduce the clutter of callback hell, or is there a deeper benefit that I’ve yet to see since this is such a simple app?

That looks good. I’m really glad you returned that second getJSON call in your promise. Promises do clean up the Pyramid of Doom quite a bit if you use them right (which you did), but they also simplify error handling. You can chain a catch method to your last then and if there is an error with any of your promises in that chain, it can be handled in that one spot. You can also sit a catch method anywhere in a promise chain and it will handle errors up to that point, then continue execution of promises from that catch onwards. This can be very useful when you have long chains of methods that do a variety of things, especially on a server, eg access the database, make an HTTP call to another server, mix the data from two different sources, then send to the client (actually a simplified version of something I did for a client this year). Different errors can happen at any point, and they’d need to be handled differently but you also want to keep the whole procedure readable and concise.

I imagine there won’t be too many errors with this Twitch app, but just so I’m understanding the importance of the catch method:

  1. If some piece of data was to not make it from the Twitch API to this app the catch would fire upon failure

  2. The catch would then fire an alert, or some type of message, to provide to the user about the error

  3. Then I would advise for some sort of resolution to the error, eg. prompt them to try a refresh?

That’s one possible flow. Exactly what an error is and what you do with it are implementation details. I believe that with the getJSON method, any non-2XX response from the server would throw an error. This is different from the fetch api, for instance, which will only throw an error if there was some problem with the network connection and the programmer is expected to handle non-2XX responses. But without making it too complicated, yes, you’ve got the idea.

So there’s no ‘cheat sheet’, so to speak, of common potential errors? I’d like to make this app as robust as possible --I’m building a portfolio to help land me a more intensive development job than where I currently work-- but am unsure of what errors could potentially arise from making calls to the Twitch API

Yeah, totally. Here’s a list of HTTP status codes. Since you’re using jQuery, don’t worry too much about sussing out errors. My point was just that other libraries and APIs may not work the same way. If you use catch as you described, you’ll be fine.

Ahh yes, I have seen this list before. I was thinking there were more specific errors that could possibly come from this API in particular

Just took a look at your portfolio, very well done! It’s impressively robust. And you’re a fellow Coloradan, very cool

I’m curious as to what your recommendations are to start learning React and node.js, perhaps some resources that got you going? It seems that all job postings for junior/mid level devs want some experience with one or both technologies.