[DING]
Welcome back to working with data and APIs in JavaScript.
So here I am building this project called The Weather
Here.
So far what I have is a web page that geolocates,
finds latitude and longitude, sends that to a node server.
The node server receives it, sends that to an API call
Dark Sky, which gets the weather information,
and then sends that back to the client here.
One other thing I want to show you
is spoofing different latitude and longitudes.
Because ultimately, this project is
going to become much more interesting
if I can manage to not just check in
at the exact same latitude and longitude over and over again.
Presumably, I'm not able to pick up this laptop
and just carry it around and walk
about the streets of New York City
to get different locations.
If I'm over here in the console, I
can actually click Escape, which brings up
this extra console shelf, drawer,
who knows what it's called.
And I could click over here with these three dots
and look for sensors.
So, by the way, this is also useful
if I want to simulate the idea of I'm
holding a mobile device that has an accelerometer for moving it
around.
But I'm going to click sensors.
And then what I want to look for is Geolocation.
So you can see there's a bunch of other things I could spoof,
but here, I want to do geolocation.
And in Override, I could say, ah, I want to be in Berlin.
So if I put Berlin there and I hit refresh,
now you can see I have the weather in Berlin.
So I'm going to use this maybe periodically, and just
check in in different locations all over the world
to save more interesting information to the database
itself.
And now let me grab some actual weather information
and display it here on the web page.
I'll create a paragraph element with some spans.
[MUSIC PLAYING]
So now I have a paragraph element
that says, the weather here is span id
summary with a temperature of span id temperature degrees
Fahrenheit, which I'm pretty sure is the units--
the measurement that I'm getting back from the Dark Sky
API itself.
So now I just want to go into my sketch.js code.
Here is where I'm actually console
logging that information.
And if I look in the browser, I can see here
that all the data that I want is under currently,
under temperature, and under summary.
Perfect.
I planned this correctly.
So now I should be able to say document.getElementById summary
equals json.currently.summary.
So I just want to take that summary
and put it in the text content of that DOM element
and then do the same thing for the temperature element.
And this is temperature.
And there we go.
So now if I hit Refresh, we can see,
aha, the weather here is mostly cloudy with a temperature
of 62.91 degrees Fahrenheit.
I'm going to change this to the degree symbol,
and I'm going to capitalize Fahrenheit.
Hit refresh again.
And I'm going to also traveled to Sao Paulo and hit Refresh.
And now the temperature in--
the weather in Sao Paolo is partly
cloudy with a temperature of 73.64 degrees Fahrenheit.
Let me also reorganize this into one paragraph.
That's, I think, what I meant to do.
All right, now I have that in one paragraph.
I like the way that looks a little bit better.
And also, I've misspelled Fahrenheit.
It should be F-A-H-R, so I should really fix that.
But I can also lazily just change it to F. There we go.
I could be satisfied with this, and I'm quite happy with this.
But I want to demonstrate to you what
does it mean to work with multiple APIs
within one application.
So I think it's useful, as an exercise,
to go and try to connect to yet another API
and get more information to add more context to this web page.
OpenAQ is an open data, open source project that aggregates
a lot of different air quality readings
from many different sources.
And you could read about their data sources,
which include government and other kind of research
institutions.
And it's important to read the disclaimer
and look at the licensing information
about how the data is collected and where it comes from.
OpenAQ has an API with a variety of different endpoints for you
to request that air quality information.
And the endpoint that I want to look at
is the latest endpoint, which I can
pass a latitude and longitude as a coordinates parameter.
And this is the endpoint-- api.openaq.org/v1/latest.
So let's just try place copying and pasting that
into our browser.
So we can see it's actually killing
us a lot of information.
So I don't want just, like, all the entire database
of air quality information.
This is a ton of information that comes in.
I want it for a specific latitude and longitude.
So it looks like, if I go back to the documentation,
that right here, under coordinates,
I can give it a property-- coordinates
equals the latitude comma the longitude.
So this should work by doing the following.
So I can go over to this URL and type in what's
known as a URL query string--
question mark coordinates equals.
Now I need to give it some latitude and longitude.
I am at 40.73 comma negative 73.99.
So I can put that in.
All right, so it looks like I'm getting an air quality
measurement from a location at Division Street, which
is this distance, probably in meters, from me.
And this is the particulate, probably,
in the air, the micrograms per meters cubed.
And obviously, I want to read through the documentation
to be a bit more clear about what these measurements exactly
are.
And I'll try to do that before I put any information on the web
page itself.
If I wanted to, I could also, say,
limit only to get measurements within a certain area,
within a certain radius, by meters.
And you can see there are a bunch of other ways
that I can sort or limit the number of data points
that I get back.
You might also notice here that this is not--
there's no API key here.
I don't have to authenticate, log in.
I don't have any, like, secret key.
And so, in essence, I could just make
a fetch request, a GET request, to this endpoint,
right from the client-side code itself.
But since I'm already requesting the weather information
from Dark Sky, from the server, let's
also make a request to here from the server, as well.
Let's grab this URL.
I'm going to go to the server code.
And the wonderful thing about using async and await
is I could just do another call to fetch right here.
So let's change this to weather_url.
Call this weather_response and weather_data.
The reason I'm doing that is because I
want to then do exactly the same sequence with an air quality
URL, an air quality response, and air quality data.
So let's put in the air quality URL, which is this,
but with coordinates equals the latitude and longitude.
Then, we're going to say fetch the air quality URL
and then convert that response into a data.
And I also need to change this to weather_url and change this
to weather_response.
So now I have weather data and air quality data.
I have both of those data sources.
All I need to do is just put them--
I'm going to put them together in another object.
I'll say constant data equals weather colon weather_data.
And then air quality colon aq_data.
And that is what I'm going to send back to the client.
Now I'm getting data from multiple APIs.
I'm getting weather information from Dark Sky and air quality
information from OpenAQ.
I should point out that I don't have to sequence one
after the other.
Because they're asynchronous calls,
they can happen somewhat in parallel.
I could use something called promise.all to wait
for a whole bunch of different asynchronous events
to all complete.
And I've actually covered this in a separate video.
You could think of this as a little exercise to yourself.
Maybe change this to use promise.all.
But with just two APIs here, I'm happy to just do
this in sequence.
Let's check to see if this works.
I'm actually running nodemon right now,
so the server has been restarted for me automatically.
Let's move to Shanghai, and let's hit Refresh.
And let's see-- ah, uncaught, cannot read property summary
of undefined.
What just happened?
Sketch.js line 14.
Ah!
So I changed the way the data comes in.
The data came in before as just the actual information
from Dark Sky.
But now, I put everything in a property called weather.
So did it console.log?
Yeah.
So you can see here I have air quality with all the air
quality information and weather with all the weather
information.
So I need to change this to weather.json.
And I don't love the way I'm doing this.
I think what I'm going to do is I'm going
to say const weather equals--
sorry, it's json.weather.currently.
I'm just going to do that.
For right now, I'm just going to say air equals
json.air_quality.
I'll have to look at what I'm looking
for in there in a second.
So now the text content here should be weather.summary.
And the text content here should just be weather.temperature.
So let's see if that works.
And hit Refresh.
And there we go.
We now have the latitude and longitude and the weather
information from Shanghai.
And let's put some information about air quality.
So in here, under air quality, under results,
I think what I'll do--
oh, there are no results.
So I suppose OpenAQ just doesn't have
any information for Shanghai.
Let's go back to New York, because I know there's
information in New York.
I guess I could do No override, and that'll get me back
to New York.
So now I've got the weather in New York, which is clear,
65 degrees.
And I can go down here and look at air quality, under results.
We can see here are my sensor readings
under zero, under measurements, under zero.
So maybe this is what I want to report.
This data is PM data, or Particulate Matter data.
And PM 2.5 refers to fine particles
are 2.5 micrometers in diameter or smaller.
So that's the concentration of those particles
within a cubic meter, or meters cubed--
micrograms per meters cubed.
Now, it's also important to be aware,
I'm recording this on Tuesday, May 21, 2019.
And the last time this reading was updated
was February 4, 2019.
So this isn't necessarily real-time data.
I assume, looking through all the different data sources
that they're aggregating, some are
updated in much more real time than others.
But for now, I'm just going to grab
whatever the first measurement is and try to get the value--
24.9-- and the units and display that on the page itself.
So what I want is air_quality.results index 0 dot
measurements index 0.
Air_quality.results index 0 dot measurements index 0.
And then I need to add another sentence to my HTML page.
[MUSIC PLAYING]
OK, I have the concentration of particulate matter
with a span is another span in the [INAUDIBLE] units last read
on date.
So I want to take that stuff from the database
and fill it in on all these spans.
So let me add a bunch more document.getElementId calls.
[MUSIC PLAYING]
And then I want to set all these particular span
elements to the correct piece of data from this air variable
up here.
So it'll be air.parameter, air.value, air.units,
and I think this one is called air.lastUpdated.
We can confirm that by seeing them all in here-- parameter,
unit, value, and lastUpdated.
So it's not units, it's unit.
OK, let's try refreshing this.
Great.
There it is.
Now we have the particulate matter reading
in this paragraph, as well.
Let's go to another location.
Let's go to Mumbai, and let's hit Refresh.
And there's our reading in Mumbai.
So this wraps up this piece of the project.
I now connect to two different APIs on the server.
I get the information, both those APIs,
pass it to the client, display it here on the web page.
Before I go into the next video, I probably
should add some form of error handling.
There's so many things that could go wrong here.
I'm not going to do comprehensive error handling
in every possible scenario, by any means,
though it's interesting to try to break this project as
much as you can and keep writing code to account for that.
But one thing I know I could do, because I discovered it
earlier, is I could go to Shanghai, where
there are no air quality readings,
and I could hit refresh.
And we'll see I get an error here.
On the one hand, as an end user, is this experience OK?
I mean, you have to ask yourself,
why am I making this project in the first place?
But at a minimum, I could be able to handle
this a bit more elegantly.
And so this is cannot read property measurements
of undefined.
That's because here, there is no measurements property,
because there were no results.
Now, what I often do in error handling
is I start to add some if statements-- well,
if there are no measurements, if the length of the array
is less than this.
But one way that I can account for a variety
of any error or specific errors is by using try/catch.
A try/catch statement is a block of code.
It's code that you want to try, and if anything goes wrong
while you're trying that code out,
you could then catch the error and execute a different code
based on what that error is.
And you can handle different errors in different ways
or any error in the same way.
I'm going to use it in the simplest way.
And I'll refer you to the MDN Web Docs to read more about it.
And I also have another video where
I cover it a little bit as part of my vid series on async,
await, and promises.
So for right here, right now, all I want to do
is I just want to try all this code.
I'm going to say try, and then I'll
put the closed curly brackets at the end.
And then I'm going to say catch.
And then I'm going to give an argument like error.
And then, basically, I can say--
I'm just going to add, right now, console.log,
something went wrong.
Now, this is not good error handling,
but you can see the idea.
Try all this code.
Anything goes wrong, spit that out.
I'll go back to the web page, hit Refresh,
and we can see, ah, something went wrong.
Now, this isn't really doing excellent error handling.
In fact, all I'm really doing is exactly what
it would do by default, anyway.
Because I could just console.error,
which will just log something, but in red.
And I could log that error itself.
So now if I hit refresh, you could
see this is basically what it was before.
But I could do something more specific
here, like I could create--
I could fill in these DOM elements,
like no reading available.
I could take this right here, and I could put this down here,
and I could say no reading.
So now if I go back to the page and refresh, we can see, well,
at least it says no reading there.
So as an exercise to you, I might
suggest that you handle the errors more thoughtfully.
Maybe you completely change what the sentence says.
And ultimately, really, something
that you won't want to do before you move on to the next video
is design this or rewrite the narrative
in a more thoughtful way.
Or try pulling other elements of data
from the air quality API or the weather
API itself to display on this page.
In the next video, I'm going to move on and work
on this check-in button.
So when I click Check In, I'm now
going to save a snapshot of all of this to the database.
Because ultimately, what I want to do is view all of those logs
plotted on a map.
[MUSIC PLAYING]
[DING]