Local Weather App (FCC Speedrun Project #6)
The Local Weather App turned out to be a three day project. Until now, I had been going along at a steady clip of about one project per day. But my modifications turned this project into a whole ‘nother beast.
When I first started the Speedrun, I knew that I wanted to do this project as a “full stack” project, making my API calls from the server. I — like many others — have been unable to find a keyless weather API. So I decided that I was going to use this project to learn to use an API key properly, from the server, without exposing it in my code. As a side benefit, this would give me extra practice using Node.js and Express, before trying to tackle FreeCodeCamp’s (fairly intimidating) full-stack projects.
So that’s what I did.
Reflections
This project got complicated much more quickly than I had imagined. Learning how to hide an API key turned out to be the easy part. Learning one thing meant that I needed to learn something else, and then some other new thing after that, until I would up with a project full of “firsts”. Here are just some of them:
- I stored an environmental variable in a .env file, and used the dotenv module to retrieve it
- I used the request module to make API requests from the server
- I used JavaScript promises to manage asynchronicity — and pass around the results of API calls
- I used a server-side template (Pug) to render HTML files
Since this project was challenging enough as it was, I decided against using the Navigator.geolocation property (which would require me to send some information to the user, then wait for their location, then get and send more information). Instead, I opted to guess at the user’s location using their IP address, and to return local weather based on that guess.
Handling environmental variables:
I was really worried that I would get this part wrong, but it turned out to be fairly straight-forward. I created a .env file — literally a file named ‘.env’ — and wrote a secret message inside. I then manually added that file to my .gitignore file, committed and pushed my changes to GitHub, and made sure that my secret message was still secret.
It was.
I then went back into the .env file, copy-pasted my actual API key inside, and followed the dotenv module’s instructions for getting it out again:
That turned out to be the easy part.
Making Server-Side API Calls:
Using Request to make API calls wasn’t that difficult either. The fact that I was already fairly comfortable with using jQuery to make API calls client-side certainly helped. API calls made using request looked similar, and certainly no more complicated:
The first parameter is just the address you’re requesting information from . I used several different hard-coded API addresses for testing. I needed to use something hard-coded, mainly because I was running this off of my own computer on my home network. And I used several mostly because it was more fun. This way, I got to see what the weather was like in Seattle, and Hawaii, and Paris, and South Carolina, and a handful of other places.
Anyway, there’s the URL, and then there’s the callback function for handling responses. It turns out that handling responses is the messy part.
Using Promises:
During my last project — the Pomodoro Clock — I struggled a bit with managing asynchronicity, and resolved to be more proactive about that going forward. With handling API calls, I found that the asynchronicity was actually easier to manage. There was never any real confusion about what order things were happening in (or at least should be happening in): I would receive a GET request from a user, then formulate and send off an API request for their location, then receive the location information (hopefully), then request the weather at that location, etc.
What was a struggle, though, was finding anything in the wild tangle of callbacks and if’s and else’s I was writing. Debugging was a bear. I think, at one point, I was spending more time counting parentheses and braces than I was actually coding.
Not. Fun.
I decided that I had to pull my code apart into functions, just to make things more manageable. And while I was at it, I figured this was as good a time as any to get some practice with promises.
I had read about promises when working through the You Don’t Know JS book series, and I had even written practice code using promises, but this was the first time that I actually attempted to use promises in the wild, to solve a real-world coding problem.
I had a hard time figuring out how to get “normal” API calls to return actual promises, and found this answer on Stack Overflow very helpful. It took me at least a couple of hours to get this to work, and then even more time to figure out error handling… but in the end, I wound up with code that was much more manageable. The code in my app.js file went from this:
To this:
Of course, much of the code in the “after” view is hidden away in other functions and modules… but that’s sort of the point. I can look at this code and see what’s going on, see the flow of my program, without getting bogged down in the details. And when I need to see the details, I can go directly to the modules and functions where they are implemented.
Using templates (pug):
Once I got that sorted, I ran into a new (and unanticipated) problem. It seemed like it only made sense to add the weather data to the website before sending it out to the user. (I think the alternative would have been asking the user to ask me for the information?) But that meant using a template — yet another new thing.
Express uses Pug in their documentation. I did look around for other other options, partly because the syntax in Pug is so different from what I was used to. But this tutorial made things a lot less intimidating, so I bit the bullet and jumped in. My HTML for the local weather app — well, the pre-HTML, I guess — looked like this:
I’m not sure that I’m sold on Pug, yet… but it wasn’t half as bad as I was expecting. It was simple to set up, and adding variables to my HTML worked well. What I did struggle with, a bit, was figuring out how to nest elements (e.g. how to put a <span> inside of a <p> element, when the <p> element also includes just plain text), and figuring out how to control white space.
But when/if I get those things figured out… I think I could get used to just sticking variables into my (pre-)HTML. And not having to include closing tags all the time. That was nice too.
Closing Thoughts
My Local Weather app definitely took longer than my other Speedrun projects, but I also learned an incredible amount.
If I were to spend more time on this project, I would start by improving handling of cases where the API calls fail to return useful or correct information. Right now I’m sending “sorry” messages, but it would be nice to offer actual webpages. Or even better, a way for the user to provide a correct location if my IP-based “guess” is wrong. That’s something that would be fairly easy to incorporate, but some other time, when I don’t have another Speedrun project waiting in the line-up.
Code HERE. No live demo, but here’s another screenshot:
Next up: Wikipedia Viewer.
(Also — I want to take a second to thank P1xt and Chance Taken. Because I’m pretty sure that without a short-term goal, a concrete deadline, and the sense of community created by the Chingu Cohorts in general, and the FCC Speedrun in particular, this project would have taken me a lot longer. There were several times where I was tempted to call it “too hard”, set it aside, and try something easier, and the Chingu Cohorts community and Speedrun Challenge gave me the confidence and determination to push through. Thank You.)