FREELessons: 29Length: 8 hours

Next lesson playing in 5 seconds

Cancel
  • Overview
  • Transcript

4.3 The Twitter API

In today's lesson, we'll review a handful of fun techniques, as we pull in tweets from the Twitter API. These techniques include templating, jQuery.map, AJAX, and code organization.

It's vital that you understand the concepts in this lesson, so, if necessary, watch it twice for good measure!

Lesson Note

The Twitter API has changed since this course was published. The material in this lesson is still relevant to the task of understanding and using JSON APIs, but the details of the implementation have changed somewhat. The source code for this lesson in the course GitHub repository has been updated to provide a working example of retrieving JSON data from a web service. See the code comments for lessons/lesson-20/index.html for an explanation of the changes.

See https://dev.twitter.com/docs/api/1.1/get/search/tweets for information about the updated API.

4.3 The Twitter API

[SOUND] In the previous lesson I gave you an introduction to templating and working with handlebars.js but now I want to take a look at a real world application where we will pull in a Twitter feed, maybe everyone that searches for Tuts+ Premium. We're going to pull in a list of those, we're going to filter through the results and display them on the page with a thumbnail and a heading and a link to the tweet itself. So we're going to do quite a bit of cool stuff, and we'll also take a look at structuring our code a little bit better. Here's our blank slate, we have a link to jQuery. We are importing handlebars, and then I have a self-invoking anonymous function. So the first step is, I want to wrap all of my logic within an object literal. So we'll call this Twitter. And make that equal to an object. And first I'll have an init method. And this will simply be, we can name it anything we want. It'll be the method that gets everything rolling. Now as you should know by now, within an object literal method most of the times this is going to refer to the object itself. So in this case, this will refer to Twitter. So if I wanna call a method called doSomething, I could either do Twitter.doSomething or I could do this.doSomething. So we're gonna set some properties on it. And the first one is the URL. How are we going to query the Twitter API? And what we'll do is keep it very simple, and we'll go to search.twitter.com. If you're unfamiliar with it, if you go to search.twitter.com you can search for anything. So if we search for tutspremium. It'll return all references to tutspremium, but instead we can tell it to return JSON so that we can use it within our application. I'll go to search.twitter.com and we'll append search.json. Lastly, we'll set the query, q for query. In this case it's bringing up a previous search but we're gonna look for tutspremium. So search.twitter.com/search.json, exclamation point, and then the query will be equal to tutspremium. If I copy that and hit return, you'll see that we get a JSON response, and this is exactly what we need. So, I'm going to hard code that in for the time being. So the next step is I want to fetch that feed. And jQuery offers an Ajax method called getJSON, and we're going to have a whole chapter dedicated to Ajax, so I'm going to be a little quick on this end, but if it's still blurry don't worry because we have a chapter dedicated to learning about Ajax. So going with the idea that each method should be responsible for one thing, I'm gonna create another method and we'll call this fetch. And this method is responsible for fetching the JSON feed. So once again within here this refers to the Twitter object, so if I want to grab the value of the URL, I could console.log this.url. We'll call the method, fetch, and when I view this in the browser, the fetch method will be called, once I trigger Twitter.init that is, and then we will log this URL. Let's make sure it's working. I go to the console and sure enough, there it is. All right, so now we're making good progress, we have nice organization for our little project. So we'll begin by using a new method called getJSON, and that means we are going to fetch a JSON feed. Now normally you'll be working locally, but there will be times when you wanna make cross-domain requests, and you'll find that there's a lot of issues related to that, but there's also a lot of ways to get around it. So we'll begin by pasting in the URL. What are we getting JSON for? Well, we're going to query this URL, that's going to return a JSON response. And then we'll execute a callback function and that JSON response, or all of this right here, we'll represent within and we'll call it data. But you can call it anything. If you want to change it to JSON, anything like that. Next I'll simply console.log data so that we can see what we're working with. But if I go to Chrome, you're going to see this. And this may confuse you. XMLHTTPrequest cannot load, and the reason is, origin null is not allowed by Access-Control-Allow-Origin. It's essentially saying, for security reasons, you can't make cross-domain Ajax requests, but there is such a thing as JSONP. And again I don't want to go over this too much in this lesson, because we'll have a chapter dedicated to it. But for now, Twitter and jQuery make this pretty easy. Twitter can accept a callback, so we can say, and call back equals an anonymous function essentially and that will be dynamically created. And then it should work. So I don't want you to worry too much about why that's the case, because again I want to teach you that in a full lesson. But for now, just accept that we can pass an anonymous function that will be triggered when we grab the feed. And that way, this will refer to our anonymous function. All right, so now let's open up this object, and you can see this is a set of the results. We have our query. We have our results. So notice, though, that what we've really want is stored within, in our case data.results. Or if we call this JSON, it would be JSON.results. So now lets change that to data.results. One more time and now we have an array of objects and each object is going to contain information about the tweet that mentions tutspremium. So you can see we have access to the profile image URL, and if we view that, you'll see that looks like just some kind of grass, but that's their thumbnail. We can also reference the tweet itself and we can see I scored 76% on the tutspremium quiz and then we also have the user, in this case opalarium. All right so now that we have everything, why don't we filter this down so that it's easy to work with? And the easy way to do that is to use jQuery.map. And what map will do is we can filter through an existing array, so in this case we're going to filter through data.results, which is this array of objects, and then for each one of those we're going to execute a function. And we will represent each object here, and we'll call it tweet. Now what we want to do here is ultimately return a new array. So we want to modify this array and return a new one. So for now I'm going to call this tweets. Tweets is going to be jQuery.map over that data.results array, and we want to modify it. So for each object, rather than returning everything, I instead want to return a subset. So we'll say return an object and we will reference tweet and let's figure out everything we want from here. I definitely want from_user, so I'll grab tweet.from_user. And we will store that within a property called author. Next I certainly want the tweet itself and we know we can reference that using tweet.text. We'll call that tweet: tweet.text. Next we want the thumbnail. And we know we can reference profile_image_url. So we'll call this one thumb, for thumbnail, is equal to tweet.profile_image_url. And then finally, we want the link to the tweet itself. View this specific tweet. And I could be wrong, correct me if I'm wrong, because I haven't researched this too much. But it doesn't seem as if they offer a direct link to where the tweet is. They simply give you information about the id. So let's figure this out. I'm going to go back to search.twitter. And we will once again search for tutspremium. And this one will be fine. I will click Open, and I want to grab the details. So what we can see here is, that it's twitter.com. And we can get rid of the hash thing, it'll still redirect there. And then slash the username, slash status and then slash the ID, and we can grab that ID right here, ID string. So let's see if we can dynamically create a link to that URL. Let's first do Opilarium. We'll replace this right here. Next, let's come back and we need to grab the ID string. So I will simply copy this long ID and paste it in right here, and now we have a link to that specific tweet. So knowing this it's very easy to build up a URL. We'll call it URL and that will be equal to http://twitter.com/ then we need the user name. Tweet.fromuser. Then slash status and then finally that ID. And we know we can reference that with ID_str. Tweet.id_str. And I think that's all we're going to need for this project. So we've mapped over the results and for each item in that array we've returned a new object. And now the results of all of those objects will be stored within a new array called tweets. So if I console.log tweets at this point, reload, you'll see that we still have an array but now we've signficantly condensed it down, and we've also added a new property called URL that links directly to the tweet. Lets double check to make sure that works. And it does, good deal. So at this point we have fetched all tweets that reference tutspremium. And at this point what we need to do is take that data and attach it to a template. Now you're going to find that when working with asynchronous actions, such as requesting data, it can be a little difficult to wrap your mind around those concepts. So I'll give you an example. Rather than var tweets let's save this within twitter.tweets. So you would think we could do this. Right? But if you're starting to catch on with jQuery you know that this is no longer going to refer to the Twitter object, because we're within jQuery's callback function. So if we were to console.log this, reload the page. You'll see that this contains information about the Ajax request. So as we know, let's cache this within a variable called self. And now we know that self will always refer to the Twitter object. And now we will replace this with self.tweets. Then at that point, when we console.log self.tweets, reload, we get that array of objects. Cool. But now you might think, well we've called this fetch method. It grabbed the data. So now even at here, I can log this.tweets and I can grab it, but, reload the page, you're going to get undefined and that's, that's a little weird. And that's something I had a lot of trouble at first, I really had trouble wrapping my mind around to why this is. I've executed this method, we've gotten some JSON, we've stored it within self.tweets or twitter.tweets, and then we execute this code. But now it's no longer available. And again, I'm gonna cover all of this within the Ajax chapter. But for now, you need to understand that getJSON, this is refered to as an asynchronous request. The same thing with set_timeout, or set_interval. These are asynchronous. Which means, this is going to execute before this completes. And to give you proof of that we will say after fetch call and then we'll say right here, console.log JSON callback. Reload the page and notice that I'm getting after fetch call and then JSON callback. One more time, after fetch call then JSON callback. So note this is executing before this is executing, and that's a little difficult to understand. And again it's because this is an asynchronous request. We're getting JSON, but because it's an asynchronous request, that means that our script will continue while that operation is occurring. So this.fetch runs, we call getJSON which is asynchronous. Then we continue on. Then this at some point, will execute and set self.tweets equal to the results. And what that means is that the point this line executes, it does not yet have access to the tweets. So now you're thinking well how, from here, within this init method, can I be sure that self.tweets is available? And what a lot of people incorrectly do is they'll set an interval. And maybe every 20 seconds they'll see, is self.tweets available? No, the Ajax request has not completed. So wait another 10 milliseconds, and then check again. And that's really bad. JQuery makes this a lot easier with jquery.deferreds. And we're not gonna do it in this lesson, because I don't want to overload you. And we'll have a whole lesson dedicated to deferreds. But for now, the basic idea is you could do jQuery.win, a specific action occurs, then do something. So when this Ajax request completes, then do this, in which case you can grab those results. But as I noted for now, I, I can't overload you cause you'll give up and I know I would give up if there's too many things going on. Such as jQuery,map, and getJSON and this object, and handlebars. It's too much. What we'll do instead, is we will trigger our template binding directly with in the getJSON callback. And that's doing more work in this method than it should. But it's all we're capable of doing right now. Right here, we know that self.tweets is the data, and we can work with it. So at that point we will call a method that binds the data. And we'll call self, and we'll call it attachTemplate. Let's create that method now. AttachTemplate is a function. Now that means because we want to attach this to a template, we need to create a template. So right up here we have our UL with a class of tweets. Within here we will create a new one. For now, we'll call it tweets-template. And within here, let's get started. We are going to have a list item. Next, we want an image that will be the user's thumbnail so, img src. Now, the alt text will be the name of the author. And notice that I'm getting that value right here. This is what we have access to within that template. Author, tweet, thumb and URL. So we have the author, the source will be thumb and the tweet itself will be stored within a paragraph. And that will be tweet. Cuz we come down, we're grabbing this right here. Tweet.text will be stored there. Now we also want to link to the tweet. So let's wrap that paragraph entirely within an anchor tag and the href of the anchor tag will be the URL property that we dynamically created. But as you'll remember, what is being returned is an array of objects. And we discussed this in the last lesson. To filter through an array of objects, we can say, for each item in the array, then create a list item, and then we'll close out our each statement. All right, our template is all set up. I'm going to store a reference to the template within the init method. We'll expand this out so we have some more room, and we'll say this.template equals, and now we have our first concern. We can definitely do this, tweet-template, and that would be fine, for small projects, that really isn't a problem. But I want you to start wrapping your mind around the idea that the more you attach your data to the DOM and the DOM structure, the more that it becomes dependent upon that structure. So you have your JavaScript. To break this code at this point, all I have to do is change the ID of this script to template. And now that will no longer work because we have this DOM access. So with that in mind, why don't we see if we can set it up so that within this object, we're not specifically referencing anything from the DOM. Those are going to be passed in to us. Okay, well with that in mind why don't we accept a config object? And that will be where we store our settings. Then, we will set this.template equal to config.template. So that means now, when we call twitter.init we pass an object. And among other things for now, we'll set template equals to tweets-template. Now, the benefits of this may not be immediately apparent to you, but they're definitely there. We called the init method and we pass in any properties that are specifically related to the DOM. And that way, this code here will always work no matter what the DOM structure is. If somebody changes it like here at the template, whoever's using it only needs to update it right here and they're good. They don't need to do anything else. They don't need to dig into this script, wherever it might be located. They simply update the config object that they patched. So for now we called this tweets-template I believe. I'll update that. Then this init method executes. Config is now equal to this object. And we create a new property on the object called template. And make it equal to config.template. There are some other ways we could do this. We could keep the config as an object and do jQuery.extend like we learned. But for now, let's not do this. Let's make it really easy to use. And the next thing we need is a reference to the container. Where is the tweets container? And that's ul with the class of tweets. So this.container, again we could do this but then we're so dependent upon the DOM, let's update it down here. Container ul.tweets. Just like that. Now we can update this, get rid of the DOM access and do config.container. Now we're ready to bind our data to the template, and we know that when we executed the callback function for getJSON, we set a property on the object, self.tweets, equal to the data. So we know that within here we can access that by doing console.log this.tweets. Let's make sure that works. Reload the page. And sure enough, we do have access to that array of objects. All right. So now this is the perfect place to bind the data to our template. If you need help with this, you can go back to the last lesson, where we discuss handlebars a little more in depth. But for now we'll say handlebars, the new global object that was created when we imported this script. And we will compile. And if you'll remember, compile wants a reference to the HTML for our template. So right down here we were just storing a reference to the script node. I'm going to update that to .html. Now if I come back, we can reference this.template. Which is the exact same thing as saying tweets-template. Same thing. But now we're not having to hard code that in. So at this point template is equal to a new function that we can execute. And this function will want to accept the context, which is the data that we're binding to it, which was this.tweets. So now, that function is going to return the modified HTML. Let's check that out. And now you can see we have all of those where we've updated the attributes as we need. So the last step is simply to append that to the container. And we know that we set this.container, that property, is equal to ul with the class of tweets. So now, I can simply say this.container.append the results of this operation. Reload the page and check it out. Pretty neat, right? So now let's do some really quick styling. At the very top, within style tags, we will say the body, let's say the width of 600 pixels on it. And center it on the page. Reload, that looks better. And the next step is, ul, let's remove those bullets. And on the list items, let's just add some breathing room at the bottom. There we go. Next, let's take the images, be very generic here. Flip it to the left, and give them some breathing room on the right. And lastly, for the anchor tags, no text decoration, and the color will be a grayish black. Reload, and check it out. So look how easy that was. With very little work, we have queried the Twitter API for all references to tutspremium, we've returned the tweet itself, a link to the tweet, we can view that right here, pretty nice, a thumbnail for the user. And then you can style this or put it in the sidebar, whatever you want to do. The only thing you'd want to do is maybe implement a form of caching which is honestly beyond the scope of this specific tutorial. Now the final thing we're going to do in this lesson, is make it so that we can pass in what we're searching for. If we come back, right here we have the URL and we're hard coding the query in. So why don't we store that within the config object instead? And we'll say query. And then tack on config.query, like so. Now, when we trigger the init method we can say the query is going to be equal to, and we will look for all references to Justin Bieber. Reload the page, and now, let's see, there's reference to Justin Bieber, if you call Justin Bieber gay. Anyways, so it's easy as that to update our code so that's it more flexible for whoever's using it. And the idea is maybe this is stored within its own file, twitter.js. Then, you import it, and you simply trigger the init method, and you pass in some settings and it'll simply work. If you decide later that you want it stored within the ul with an ID of biebster-tweets then you only need to take that value and update it below where you referenced the container. And that way the script always knows what it's working with. Reload the page and it still works wonderfully. All right and I think that's gonna do it for today. We did a lot of stuff here and I really want you to focus on this lesson, so if it was blurry, go back and watch it again, because we, we did quite a bit. We focused a lot on good structure for our code. For small projects like, this an object literal, that will contain all of your methods and properties, is a great way to go. We've wrapped this within a self-invoking anonymous function. That way Twitter is not available to the global space. And we've set up configuration options. We've learned how to query the Twitter API. You've had a crash, crash course in working with the getJSON method, which you'll learn about a little bit more. Now if you wanted to take this further, and we will, we would want to take this out and learn how to use jQuery.deferreds so that we don't have to make the fetch method handle way more than it needs to. You'll find with a lot of projects because the author doesn't know how to use jQuery.deferreds, they end up storing all of their logic within the getJSON callback function. Because they don't how to access it and they don't know how to deal with these asynchronous requests, and when self.tweets will be available and when it will not. So when you wanna learn more about that, wait until the jQuery.deferred lesson in this course. I'll see you later. Bye.

Back to the top