تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

Laravel HTTP client basics0:00

If you need to make requests to an external API, we can make use of the HTTP client which is built right into Laravel. It's a wrapper around the Kuzzle package and has a lot of really useful features, so let's take a look at how we can use it within our demo app. So say for example we have a page where we want to show data from a variety of external APIs. So I have that set up here already, let's take a look at an example request. So we can just make use of the HTTP facade, and we have different methods for the different HTTP verbs like GET or POST. And once we have this response object, we have a bunch of handy methods we can make

HTTP verbs like GET or POST. And once we have this response object, we have a bunch of handy methods we can make use of. So if we wanted the JSON data being returned, we can make use of the json method, and this will convert it to an array which we can make use of. If you wanted to work with collections, you can call the collect method and convert it to a collection. If you want a status, you can make use of the status method. If you want to check if the response was okay, you can use these methods, and you can also grab the errors if you need them.

Requesting GitHub repos0:53

If you want to check if the response was okay, you can use these methods, and you can also grab the errors if you need them. So let's grab this code here, and let's make an example request. So I'll do it right here. We'll make a few requests here, so I'm going to rename the variable to response. How about we work with the GitHub API for now. Let's import HTTP, and the endpoint for GitHub is api.github.com. And we'll grab a list of my public repos, so it's users, my username, and repos. Now it also accepts some query params, which you can either pass as an array for the second param, or you can just do it directly within the URL.

Now it also accepts some query params, which you can either pass as an array for the second param, or you can just do it directly within the URL. So I'll just do it that way. So I just want to sort it by the most recent, so sort equals created. And I just want 10 results, so perPage equals 10. Okay. So now we have this response object, and we can use any of those methods. So how about we just dump the status. That should be a 200 if I entered the endpoint correctly. And how about another one for if it's okay, and that should be true.

That should be a 200 if I entered the endpoint correctly. And how about another one for if it's okay, and that should be true. And how about one for the actual data? Okay. So let's try that out. Back here. Refresh. So you can see we get a 200 response for okay, the response was okay, so it's true. And here is our data. And of course, you can use this however you like within your Blade views.

And here is our data. And of course, you can use this however you like within your Blade views. So let me pass that in to the view here. Let's just remove this. And you definitely want to do some error checking, but I'll just pass the data in directly for now. And how about we say response. And we'll pass in response GitHub JSON. Okay, let's save that. Let's go into our view.

Okay, let's save that. Let's go into our view. And how about we add a new section here? Let's add an h3, make it a bit bigger, and somewhat bold. And let's say repos from API. And I'm just going to paste in a block of code here. So we have a for else loop. So if there's at least one repo, it will list them here in this list item. And if not, it says no repos found. And you can see we're just looping over our repos here.

Calling weather API3:14

And if not, it says no response found. And you can see we're just looping over our responses here. So let's save that. Let's see if that works in our blade view. And there are our responses. Okay, let's add a few more here because I want to show you a few more features. So back to our routes file, I'm going to add another request for the weather. So we'll name it responseWeather. And it's coming from the OpenWeatherMap API. And you can see here's the endpoint.

And it's coming from the OpenWeatherMap API. And you can see here's the endpoint. I do have some query params here for the city I want to select, also the units. And for authentication, it requires the appId to be passed in. So you can see I have appId here. It's referencing the array within services OpenWeatherMap appId. So within services, you can see I have it defined here. And within my .env variable, or environment file, you can see the key here. Okay. So let's see if that works.

Okay. So let's see if that works. Again, let's just dump the response weather. And let's just grab the actual data. Hopefully, the endpoint is correct, as well as the key. So let's save that. And let's see if we get information about the weather. Okay, and we do. And we have a bunch of data here, but I'm only interested in the temperature here. So it'll be within the main temp key.

And we have a bunch of data here, but I'm only interested in the temperature here. So it'll be within the main temp key. And I'm also interested in the description. So within the weather key, we have this array, and we have a description. So again, we can pass this into our Blade view and make use of it from within there. So let's say weather here. And it should be response weather. Let's get rid of this dump. And let's make use of it within our Blade view. So within here, we can duplicate this.

And let's make use of it within our Blade view. So within here, we can duplicate this. And just output the weather in this block. So let's say weather from API, I no longer need an unordered list. And let's make another section in here and say mt4. And this will have the temperature, so say temp. And I passed it in as a weather variable, the temperature was within a main key. And that's within a temp key, okay. And let's do the same for the description. So the key was weather.

Bearer token movie API5:30

And let's do the same for the description. So the key was weather. It was the first item in the array. And there was a description key. Okay, let's try that out. And we do get the temperature down here. Cool. And let's take a look at one more API here, which makes use of bearer tokens. So this will grab a list of movies coming from the TMDB API. And you can see there are two ways to authenticate your request.

So this will grab a list of movies coming from the TMDB API. And you can see there are two ways to authenticate your request. We can pass in the API key similar to how we just did. Or we can pass in a bearer token. So let's take the bearer token approach. And let's list out some movies. So back to our routes/web.php. So you can see we're making multiple requests here, which can potentially slow down your application. But we'll take a look at how we can do these concurrently in a second.

application. But we'll take a look at how we can do these concurrently in a second. So let's call this one responseMovies. Actually, let me just paste in the endpoint here. And you can see we're making use of this withToken method, which passes in the bearer token for authentication. And again, that's coming from the services file within the TMDB bearerToken key. So right here, and that's within my .env variable as well, right here, okay. And this is the endpoint, it's grabbing a list of popular movies. So one more time, let's just dump that to make sure it's correct.

And this is the endpoint, it's grabbing a list of popular movies. So one more time, let's just dump that to make sure it's correct. So $response, $movies, json, okay, save that, let's make sure we get that list of movies. And we do right here within a results key. So again, we can pass that in and make use of it in our Blade view. So let's duplicate this. Now it's $movies, it's $response->movies, let's get rid of this dump here. And let's make use of it in our Blade view. So it's almost the same as this one here. So I'm just going to grab this and let's paste it underneath here.

So it's almost the same as this one here. So I'm just going to grab this and let's paste it underneath here. Now it's movies from API. So the key was movies results. Okay, as movie. And we can just list out the movie title. So let's change this to movie title. And hopefully I did that right. Hopefully the bearer token is being passed through. Actually, it is already because we do get our list of movies here.

Hopefully the bearerToken is being passed through. Actually, it is already because we do get our list of movies here. So if I were to pass an incorrect token, just to show you it doesn't work, let's put a dump back. And go back to my .env variable. And let's just put something in here, which is incorrect, okay. And let's refresh that. And we are getting an undefined results. Let's just dump this. So instead of dump, let's just dump it to see what we get.

Let's just dump this. So instead of dump, let's just dump it to see what we get. And you can see we do get invalid API key. Okay, let's put that back. And let's see if we get actual movies now. Oops, we got to remove the dump one more time. And we do. Cool. Now let's take a look at macros which can dry up some of our code. So if we had multiple requests to some of these endpoints, say we want to show different

Creating HTTP macros8:42

Now let's take a look at macros which can dry up some of our code. So if we had multiple requests to some of these endpoints, say we want to show different types of movies here, we would make several calls to this API with different endpoints. So we'd be repeating the withToken call for each call. And also the base URL will be the same for each call. So that code would be repeated. And if you want to dry that up, you can make use of macros. So we can define a macro where that repeated code can go. For example, we can define the base URL in there, we can define any headers, or in this case, it's going to be our token.

For example, we can define the base URL in there, we can define any headers, or in this case, it's going to be our token. So let's grab this. It's going to our AppServiceProvider. And let's put it within our boot method. So let's put it underneath here. Let's save that. Let's import HTTP. And let me just indent this. So we can add our token call in here.

And let me just indent this. So we can add our token call in here. So let me grab that from our routes/web.php. Let's grab this with token call. Okay, we can put this within our macro. So I'll put it right here before the base URL. Okay. I think this needs one more bracket. And it's also update our base URL. So it'll be this part of the endpoint.

And it's also update our base URL. So it'll be this part of the endpoint. So up to the three, let's put that as our base URL. And let's see if we can make use of this macro now. Save that. And if we go back to our routes file, let's just comment this out for now. Actually, let's duplicate that. And we can just make use of that macro now. So we can say http movies is what we called it. And it's a GET request.

So we can say HTTP movies is what we called it. And it's a GET request. And we can just provide the endpoint without the base URL. So in this case, it's /movies, or /movie/popular. And everything else is tucked neatly within the macro. So if I did this correctly, let's save that. And let's try that out in the browser. Movies does not exist. Did I not change the name maybe? Yes, I forgot to change the name here.

Did I not change the name maybe? Yes, I forgot to change the name here. Change it to movies. Save that. And hopefully this works now. And it does. So yeah, definitely make use of macros when you have multiple requests with a lot of repeated code. Next up, let's take a look at concurrent requests. So depending on how many requests you have, this may help with performance.

Concurrent requests and testing fakes11:05

Next up, let's take a look at concurrent requests. So depending on how many requests you have, this may help with performance. So the way php works is that requests happen one after the other. So in our code, go back to our routes here. Say for example, the GitHub request took a long time. Say this took two seconds. This took one second. And the movies took one second as well. The response would take four seconds because they happen one after the other. Now if you do it concurrently, we can fire off the requests at the same time.

The response would take four seconds because they happen one after the other. Now if you do it concurrently, we can fire off the requests at the same time. And the request will take only as long as the slowest request. So in this case, the slowest is GitHub, and that would be two seconds. And that's how long these three requests would take instead of four. So let's see how we can do that. Actually, before we do that, let's benchmark our current response time. And I am making use of Laravel Debugbar down here. You can see the request time or the response time right here. So let's refresh a few times to see how long it takes.

We just put them within this closure and make use of the pool method. And then we can access them like this on the array. Or I believe you can give them names as well. So you can access them with keys instead of indexes. So let's do it this way. And let's group our requests together. So let's paste that in here. Let me just save that. OK, it did not indent. So let's do it manually.

OK, it did not indent. So let's do it manually. Let's make sure to import pool. OK. And again, this is just a wrapper around Guzzle. Let's name this one GitHub. This one's going to be weather. And this one will be movies. And we can just grab the respective endpoints and put them within here. So let's grab the one for GitHub and paste that in.

And we can just grab the respective endpoints and put them within here. So let's grab the one for GitHub and paste that in. Let's grab the one for the weather and put that in as well. And for our movies, we can't use our macro anymore because it's grouped with the other requests. So let's just grab what we had before. So all of this. Put that in here. And now when we're passing it to our view, let's just make sure to use the array instead.

And now when we're passing it to our view, let's just make sure to use the array instead. So it's going to be responses. And this one is a key of GitHub. And the same for the others as well. And let's save that. Hopefully, everything is still working correctly. Actually, let's remove these requests now since we're no longer using them. It's now within our pool. Comment these out.

and only takes as long as the slowest request within the pool. The last thing I want to take a quick look at is testing. So a lot of the times, you don't want to make network requests within your tests as that could slow them down. Or you can have a different response based on what you call it. So in those cases, you want to fake your HTTP request. And Laravel makes that really easy. So in this case, we want to fake specific URLs. And we can do that as well. So we want to fake our different endpoints here.

And we can do that as well. So we want to fake our different endpoints here. So one for GitHub, one for our weather, and one for our movies. So let's just make use of the example test within Laravel. And we'll write some tests within there or one test. So we'll just make use of this. Let's use the refreshDatabase trait. Use refreshDatabase, okay. And we are calling the HTTP client endpoint. And if we didn't use fakes,

And we are calling the HTTP client endpoint. And if we didn't use fakes, it'll actually make a network request. So let's say for example, response assert C. How about we assert one of our GitHub repos? So let's take a look at one of them here. Let's just grab this one here. Okay, and that should be on the page as it is making a network request. We'll save this.

as it is making a network request. We'll save this. Let's test that. And we do get green, but that did take a while. So let's go ahead and fake that endpoint. So if we go back to the docs, let's copy this and let's fake our endpoints. So up here we can call that fake method. And let me just reindent this. Let's import HTTP.

And let me just reintent this. Let's import HTTP. And in this case, we do want to fake a GitHub response. So let me just paste in what I have here. And you can see I'm returning a similar structure to what GitHub actually responds with. But in this case, we're only interested in the name. So I fake these two repos here. I'm faking a 200 response. And now we can assert against that data.

I'm faking a 200 response. And now we can assert against that data. So now we can say myCoolRepo one and also two. And let's get rid of this Google one here. And now this should work as well, but it should be faster as we're no longer making a request and we're making use of fakes. So let's save this, let's test this. And we are at green and it's much faster.

So let's save this, let's test this. And we are at green and it's much faster. So I'll do the same for our other two endpoints and we'll assert against that data as well. Okay, so I pasted in some fakes for our other endpoints as well, one for our weather and one for our movies. And again, I'm mimicking the same structure that's actually returned in the real response. So for the movies, for example,

that's actually returned in the real response. So for the movies, for example, we had this results key where our results were stored. So now we can assert against this data. So we can assert that we see broken clouds and the temperature, so let's add that. So this is broken clouds and the temperature was 27.1. And we can also assert against movie one and movie two. So let's just duplicate these. Let's assert movie one and also movie two.

So let's just duplicate these. Let's assert movieOne and also movieTwo. And if I did everything correctly, this should pass. And it does. So yeah, definitely make use of fakes when you're testing your HTTP calls. So yeah, that's gonna be it for this episode. Let's make our final commit here. So we'll git add. This is episode 12.

HTTP MacrosConcurrent RequestsTesting with Fakes

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟