API Interactions with Node
Coming from React, I expected to use the fetch function to make API calls but to my surprise, the process is a bit different. The great thing about knowing the fundamentals of using an API is that the logic is the same for the most part. You know that you’ll need an endpoint to make a request to and then you want to do something with the response.
The Project
Currently, I’m working on a weather app that will tell me the weather to a certain city. Right now it’s a command line application so when I run
node app.js "Boston"
I get a response saying something like “Partly Cloudy. It is currently 60 degrees in Boston”.
The Resources
I’m using two API’s that depend on each other to get my information. The first is weatherstack.com which is a real time worldwide weather data api. The second is called mapbox.com which allows us to translate an address to coordinate points.
Weather stack as it stands needs to know the coordinates of the area you’d like to gather information about. I don’t expect my users to know coordinates of New York City if that’s what they’re looking for. That’s why I’m using mapbox!
Implementation
Let’s start with mapbox. I’ll create a function called ‘geocode’ and we want it to take in an argument that is a string as well as a callback function. Inside of it lets make a request to mapbox, parse the api, and then do something with the return value.
const geocode = (address, callback) =>{
const url = "<enter url>" request({url:url, json:true}, (error, response)=>{
if(error){
}else if(){
}else {
}
}
)}
Now that we have the skeleton, let’s break this down. The address is the input like “Boston” that will tell this api what the place of interest is. The callback is a function that will be called later.
‘Request’ is an npm package that makes it incredibly easy to make api calls and is similar to my experience using fetch. You provide the url or endpoint where the information is held and set json to be true. This will parse your information and your response will be in JSON format. Now I have three conditionals.
The first is if the program encounters and error, we’ll want to tell the user that there was an error somehow. The second is for a successful connection to the endpoint BUT an error regarding the input which will result in a JSON object with an error key inside of it. The last conditional is non-error catching when the response is exactly what we were hoping for.
const geocode = (address, callback)=>{const url = '<enter url here>'request({url, json:true}, (error, {body})=>{ if(error){ callback('Unable to connect to location services!', undefined) }else if(body.features.length===0){ callback('Unable to find location. Try another search', undefined) } else{ callback(undefined,{ latitude: body.features[0].center[0], longitude: body.features[0].center[1], location: body.features[0].place_name }) }})}
Beautiful, so the callback always takes two arguments. If an error is present than a response is undefined, and when a response is present than the error argument is undefined. In the last conditional, when there are no errors, we’re passing along the coordinate points to the callback function.
So now let’s use that information. We’ll create another function called forecast and that calls on weather stack and will give us the weather details from the coordinates we receive from the geocode function.
const forecast = (lat, long, callback) => {const url = `<enter weatherstack url here>`request({url, json:true}, (error, {body} )=>{ if(error){ callback('Unable to connect to weather service',undefined) }else if(body.error){ callback('Unable to find location',undefined) }else{ callback(undefined, body.current.weather_descriptions[0]) } })}
The forecast will take the latitude and longitude provided from the geocode function and a callback. Same as before, three conditionals for error handling. The last conditional is our expected result which returns a description of the weather in the place of interest.
Lastly, we need these two function to interact with each other. The callback function inside of geocode will be forecast.
const address = process.argv[2]if(!address){ console.log("Please Provide A Location")}else{ geocode(address, (error, {latitude, longitude,location}={})=>{ if(error){return console.log(error)} forecast(latitude, longitude, (error, forecastData) => { if(error){ return console.log(error) } console.log(location) console.log(forecastData) }) })}
In a separate file like app.js, first thing we’d like to know is if a location has been entered. If it hasn’t let the users know that they need to with “Please Provide A Location”. If they did, geocode is called with that address and we expect the response to be the latitude, longitude, and location. If no errors are present, we call on forecast which uses the responses from geocode. If there are no errors, we console.log the forecast Data and the location. If everything was done correctly, you should see the location and weather of the town.
Conclusion
Regardless of your experience with JS, node’s request module makes it incredibly easy to make api requests. This one was particularly tricky because the requests are almost nested which is why we used callbacks in our functions. I hope this helps! That is it for this weeks blog, as always happy coding!