Introduction & Project Demo
Hello guys. Quite recently I discovered a free API to get the weather, and I decided to make a demo project with Laravel on how to get that API. It is free and no API key is required. So in this lesson, I will show you a demonstration of using this API. Here's the documentation. So you choose the Berlin, the city or coordinates, you choose what you want, and if you click preview, this chart is updated and the whole API works like this. So you load the URL with latitude and longitude, and the result is something like this, so JSON result, pretty typical, right, for us Laravel developers.
And I asked my colleagues to create a demo project for that, and this is how it looks. It's using the same API but takes only some amount of data and shows a table instead of a graph. So if you choose London, for example, it shows max temperature and min temperature for seven days ahead. If you choose New York, the numbers are different, and they come from the API.
So I will show you the code, and also it will be a lesson on Alpine.js, because to load that API on change, that is a perfect example of a small library like Alpine.js instead of using a full framework like Vue.js or older jQuery, because it all happens then in the Blade file directly, almost like inline JavaScript but more structured.
Backend: Laravel Routes and API Controller
Let me show you how. The route is really simple. We're just loading the home blade. Every other route is from our boilerplate based on Laravel Breeze. I will link that in the description below if you want to find out more about that. So we'll go directly to home.blade and that home.blade contains some Alpine.js code, but what you need to know for now, and I will get back to Alpine.js, is on change of that select value, on the city change, we call getWeather function, which is down below, and it fetches /api/weather with the city parameter.
Then we go to routes/api.php, and we have weather/{city}. We have city parameter and a separate API controller for the weather. And this is where we get to HTTP Client of Laravel to perform API requests to third-party services. In this case, we're performing a really simple GET request. So Http::get. We don't need to install anything for that, no cURL or any external library like Guzzle. We just use facade Http, and it is automatically injected, if I do that in PhpStorm for example, like this. And then we get the URL with parameters that are coordinates. Those parameters are in the config of this application. So we've kind of hard-coded three cities at the bottom. So London, New York and Tokyo with their coordinates. And then we get that API results with coordinates, choose only the things that we need like temperature.
And then that Laravel HTTP client provides a few methods to decide if the response was successful. So you could check of course manually status code so you can do response->status() and check if it's 200 or not. But Laravel HTTP Client, and I've opened the documentation here, provides with more readable methods. successful() means 200 or 200-something. failed() means 400 or 500 from the response. And then if you want to distinguish between whether it's 400 or 500, there's clientError() and serverError(). So it's much more readable. So in our case, if it's successful, we return the JSON that is coming from the API. Otherwise, we return empty. Of course, in other cases you may return a separate variable like error: true or false, but this is a simple example and we will handle that in the JavaScript in Alpine.js, whether it's empty or not.
Optimizing with Laravel Cache
Important thing here is the cache. If some data from an external service doesn't change that much, like the weather, it's worth to save it in the cache locally so it wouldn't perform too many API requests, because it may hit the limit of number of requests allowed by that service. So you can do Cache::remember() and this is the amount of seconds as a parameter. So it means it is remembered for five minutes. Then this is the parameter, the cache for city, and then city ID or city name.
And then next time, Laravel will check whether it is in the cache, and if cache is not expired in five minutes, then it will return the data from the cache. Otherwise, it will get another set of data from the API and put it into the cache for another five minutes.
A Quick Primer on Alpine.js
Now let's take a look at the front end with Alpine.js. For those who haven't started anything with Alpine.js, I'm on the home page of Alpine.js, and here's the real working example of the Alpine.js with really small interaction, but this is enough to get the dynamic data in JavaScript. So you don't need to load jQuery or perform npm commands with Vue.js. All you need to do is load Alpine.js from the CDN.
Then in any of your HTML tags, you can define x-data which is variables that you will work with in that block of HTML of the Blade in our case. And then you define @click, which can be @change in our case, it would be @change for the dropdown, and then inside, you just write JavaScript code what should be changed. So open: true refers to this being true now. And then x-show="open" means that this should be visible if the open is true. So that's it, really small example for Alpine.js. I have a bit more in-depth video and I will link that in the description below, seven minutes introduction to Alpine.js, but you get the idea. In our case, the example will be a bit more complex, but the core stays the same.
Frontend: Building the Alpine.js Component
Let me show you. So our home Blade is with x-app-layout, which means if we go to app.blade, layouts/app.blade, and this is Laravel Breeze structure by the way, all we need to do to load the Alpine.js, we just load it from the CDN. Of course there is a way to do that via npm and you can read the documentation for that, the documentation of Alpine.js, but we will do it the CDN way for simplicity.
And then in our home Blade, in that div for the data, we have x-data="weather()" and weather is a function. You could define that inline, but I decided since it's a bit more complex to offload it to a separate function. And you can define that function down below in the script like in JavaScript. So you define the function which defines the variables for those interactions for that block. So what variables do we need? City, we need weather data, loading or not the indicator, and then error or not. And these are default values. And also you can define the functions. So in another example of Alpine.js docs, you can define x-data as parameter, comma parameter, comma parameter, like variable, and then a function just in line. So in my case, a function is just a bit longer, so I decided to first offload it here and second expand it into more than one line.
So this will be called on the change of the dropdown. And let's go back, let's go up, and here we have our dropdown of cities. First it has x-model="city", similar to Vue.js if you worked with Vue.js, it's v-model. So it's x-model which means that each time the select is changed, it will change the value of city. And then @change, getWeather.
And that getWeather does what? First by default, the error is clear, and the weather is empty. If we don't have any city, we just return and don't do anything. But if we do have the city, we have loading = true, which shows the loading indicator, and then we fetch from the API, but from our API, which in turn calls the external weather API. And then we process the data. If we don't have that variable, which means our array is empty, remember in this case, so if we have this case, then we have error. Otherwise, we fill in the weather, and loading is false.
Now, where are those variables used in the Blade? So this is the loading indicator. It's just dot dot dot, like a loading indicator. And we have x-if, which means that this will be shown only if loading is true. Next, same logic, if error is not empty, we will show the error with red color. And then if it's not loading, we have the weather data in the table.
And Alpine.js allows you to have for loops. So for, x-for. weather.time, so we have day as a column header, and we have x-text of day, which will become the value of that span. Next, we have table body and again, for loop, weather.temperature_2m_max, and again, max, and it becomes x-text max. Similar to min temp, also x-text min that comes from weather.temperature_2m_min.
Live Demo: Caching and Error States
I will again show you how it works. So if the page is loaded by default, city is empty, error is empty, weather data is not present. And then as soon as we change here, we have city value, we have loading indicator, have you seen those dots really briefly? And then we have that table because we have weather data, the error is empty, the loading is false by that time. And then if we change that to other city, again loading indicator, data comes from the API. But now if we choose London, it is almost immediate because it comes from the cache and doesn't even call the external API. And if we choose select city, everything is empty like in the initial state.
And I haven't shown you the error. So for example if we made some typo of loading something else from the API, we refresh. We select London. Oh, it comes from the cache now. So that's the proof for you. So it didn't even call the external API. But if I choose a city which wasn't present, we will have 'Error happened when fetching the API'. So that's it.
Conclusion and Further Learning
The code repository will be available for free on Github as usual. And if you want more lessons from me about all sorts of topics around Laravel, I have a yearly membership for my courses, which is currently 21 courses. I will scroll down. So SOLID Code, Queues in Laravel, Database Structure, Livewire, Vue.js, API, Eloquent, Structuring Laravel Project. Some of the courses are quite old but still mostly relevant. So if you want to get all of those, there's a membership fee, or price rather, at $99 per year. And if you wanted to buy those courses individually one by one, the total price is almost $500, so yearly membership totally pays off because you'll get not only current courses but everything I will release for a year ahead. Currently in my plans, there are two topics of Laravel plus GraphQL and then real-time thing with Laravel Echo, Sockets, and stuff like that. So if you want to get those, yearly membership is the best deal you can have. And see you guys in other videos.