I'm making a course on Laravel Sanctum: MasteringAuth.com

Fetch and save Youtube video details in your Laravel application

Constantin Druc ยท 15 Oct, 2021

[00:01] As a starting point we have the talk model and its migration; and this is where we'll be saving the videos. We have title, duration, embedHtml, thumbnail, and so on. Now, before you do anything, make sure you have a valid api key and that you've enabled youtube data api in your google cloud dashboard.

[00:21] Now let's open the terminal and create a new test using php artisan make:test YoutubeTalkTest, let's open the file, remove the boilerplate, and add a new test called it_saves_youtube_talk_to_database.

[00:42] To fetch the details of a youtube video we'll need the video id, then to store the details in the database, we'll need a talk model. Finally, we could have a new YoutubeTalk class that will receive the video id in the constructor, and then save the details into the talk model. Then, for the assertions, since we are dealing with external data that may or may not change, we cannot rely on checking the exact values we'll get back; we'll just have to settle by checking that all the required columns have been filled. So we'll do this assertNotNull talk title; to make this faster, I'll go inside the migration file and grab the rest of the columns.

[01:32] Now here I'll do $this->assertNotNull talk, and now let's check these, the description can be null and so does the approved_at column, but all the other ones are required. Now let's create the YoutubeTalk class, I'll go inside my models and say new file YoutubeTalk.php and then we'll have namespace, app, models, and then class Talk. Inside the constructor we'll receive the id of the video, which will be a string, and let's initialize the properties. And then, we'll have a save method that will receive a Talk model. So what should the save method do, it should make an api request, prepare the talk data, and then save it.

[02:33] We'll start by writing everything here and then later on we'll see how we can refactor it into smaller methods. Let's make the api request. We'll do response equals http, and we'll use the facade, as json, because we want the json response, get and the url we need to call is this one. Then, as parameters we need to send part, and this instructs youtube on what kind of details we want back, and we want snippet, player, and content details. Then we need to send the video id which is this id, and finally our api key.

[03:22] Now, the response object comes with a very handy json method we can call. Let's see what we get back if we run the test. Let's import the youtube talk class first and run this test.

[03:39] We'll see that we get back an array of items. Now, since we've used an id, this array will never have more than one item in it. Here we have the id of the video and under snippet we have the publishedAt date, title, description. Down below we have the thumbnails, the tags, but we don't need those, then we have the contentDetails where we have the duration of the video and the embedHtml which is under player.

[04:11] Now, let's move to the second part which is start building the array we need to save the talk to our database. I can go inside the migration file and grab this one as well, go back to our YoutubeTalk, and let's say we have a data array with all of these.

[04:37] The coolest part about this json method is that it also supports that notation. So to get the title we can do something like, let's look at the array first, and we have items.0.snippet and then title. So to get the title we can do $response->json('items.0.snippet.title'). For the duration we can grab this, and then following along, we have item 0 and then contentDetails.duration. So we have item 0 content details and duration; and I'll do the same for the rest of the fields, but let's speed this up.

[05:36] Now if I die and dump the data, remove this one right here, and run the test, here it is: we have all the information. One problem is that the duration needs to be an integer representing the duration of the video in seconds, so we'll need to convert this. We'll use carbon interval, and then make, and then call the totalSeconds, and here it is.

[06:07] Another problem we have is regarding the thumbnails. If I die and dump the response, rerun the test, scroll down, we'll see that we have many different versions of the thumbnails. The problem is that for some videos some thumbnails may not be available, so we'll have to extract a method that will return, by default, the standard thumbnail. Otherwise it will go through this collection and return the image with the highest resolution. So let's do that. I'll go here and replace this with this thumbnail url and pass in the response, and then we'll add the method. And here if we have a standard url; we'll return it, otherwise we'll collect all the thumbnails, and then we'll sort them descending by their width, grab the first one, and we should return the url. But to make sure this doesn't blow up, we'll wrap this part in an optional call. Let's rerun the test, remove this one right here, rerun, and there it is.

[07:50] Now that we have the required data, we can continue with saving the talk. We can do talk, and then fill with this data, and finally save.Let's rerun the test, and it passes.

[08:07] Let's start refactoring this bad boy. If we take a look at this response all we do is calling the json method to get the value for a specific key. So we can grab all this and put it in a json method on our object. So let's copy this and say private function json that will receive a key that may be null, and then do this, and return json response json and passing the key. Now here we can remove this part, and here we can see this json, and if we scroll down to the thumbnail url we can remove this, and replace it with this.

[09:05] Let's rerun the test, and it still passes. Now this looks a bit better, but we've introduced a new problem. Every time we are calling the json method we are making a new http request. To prevent this from happening we can use a technique called memorization. The idea of this technique is to speed up function calls by storing the result of the initial function call and then return that result on any subsequent call of that function.

[09:38] So let's add the new response property to our class. We'll do private response which will be an illuminate http client response, and then store the response of our http request. We'll do this response and then this response, and finally to make this work we'll need to check if we set the response. So if we set this response, then return this response json key, otherwise make the request and call the json method on the response object. To check this let's add more dump here, and this should only be called once. Let's rerun the test and here it is.

[10:32] One thing we need to take into account is that the youtube api may go down so let's protect against that. We'll do if this response failed we'll throw a new exception. We'll do throw new exception FailedToFetchVideoDetails::for and this id.

[10:59] Then, even if the request is successful, the data we get back may be invalid, so let's validate it. We'll do validator equals validator, make, we'll pass it the data this response json and then to validate it, let's grab the keys from here, and the title is required, the duration is required, the embedHtml is required, the description doesn't need to be present, but the publishedAt date does, so required, and it needs to be a valid date. And then we also need to check the thumbnails. And here we need to have at least one thumbnail. And now here, we have if this response failed or validator fails. So now we are covered.

[12:16] Let's remove this call right here, and I think we can clean this up, and then save. And that's about it. Oh, we can move these into the services config file, so here we can do config services youtube and let's say endpoint and grab this. Let's go to our services config add youtube, endpoint, and let's say we may have an env variable, so we'll do youtube endpoint and set it. We'll also have the secret which is the api key.

[13:37] Let's rerun the test again and it still passes. And that was it that's how you can fetch and save the details of a youtube video in your laravel application.