Using a 3rd Party API

Sometimes we will need or want to rely on external sources of data to extend the functionality of our app. To do this, we can use an API, or Application Programming Interface. The term “API” is used basically anywhere we’re talking about how we interact with a library, framework, or service. However, it most commonly refers to what endpoints are available on a backend application. Technically, we are building an API by creating routes with express , but our API isn’t meant for other developers to use.

But fortunately for us, there are plenty of free 3rd party APIs we can play with, so for this tutorial, we will use the nexchange.io API and display some basic cryptocurrency information. Usually, using a 3rd party service like this cryptocurrency API requires you to register and receive and API Key. This makes sure the company that maintains the API can prevent people from abusing their service. More on that in another tutorial, for now, we can just explore what data nexchange.io is allowing us to see.

Go ahead and visit https://api.nexchange.io/en/api/v1/currency/ and you’ll see the response we get from their servers. The long array of data contains some basic information on a wide range of currencies, and when we call this endpoint from our app, we will have direct access to the same information. So, how do we go ahead and make that request?

We will use something called fetch , which is built directly into the Javascript runtime you’ll find in browsers. Unfortunately, Node doesn’t ship with it by default, but we can practice our dependency management skills by adding it. Go ahead and install the node-fetch package. I won’t tell you how to do it, but you can refer to earlier sections of the tutorial if you can’t remember how! Oh, and don’t forget to import the dependency:

var fetch = require('node-fetch');

Once we have node-fetch installed, let’s update our root route function to look like the following snippet:

app.get('/', (req, res) => {

const code = req.query.code;

.then(cryptoData => cryptoData.json())

.then(cryptoData => {

return code ?

cryptoData.filter(crypto => crypto.code == code) :

cryptoData;

})

.then(cryptoData => {

res.render('home', { cryptoData: cryptoData });

})

.catch(err => console.log(err))

}); fetch(' https://api.nexchange.io/en/api/v1/currency/' .then(cryptoData => cryptoData.json()).then(cryptoData => {return code ?cryptoData.filter(crypto => crypto.code == code) :cryptoData;}).then(cryptoData => {res.render('home', { cryptoData: cryptoData });}).catch(err => console.log(err))});

Whoa! Okay, this is different. The most noticeable difference seems to be the repeated call to then . This is because fetch returns a Promise. Javascript developers use promises to handle asynchronous code, which just means that it runs in the background, and we won’t know exactly when it’s finished running. Web requests are always asynchronous because sending data between servers always takes different amounts of time to execute.

Normally, code runs in the order it’s written. Line 1 is executed, then Line 2, then Line 3, etc. Asynchronous code throws a wrench into this pattern, though, and things can get confusing fast if we aren’t exactly sure of what happening. When dealing with async code, it could be the case that Line 1 is executed, then Line 2, then Line 4, then Line 3! For example, why wouldn’t this code work?

app.get('/', (req, res) => {

let data;

.then(cryptoData => cryptoData.json())

.then(cryptoData => {

data = cryptoData;

})

.catch(err => console.log(err)); fetch(' https://api.nexchange.io/en/api/v1/currency/' .then(cryptoData => cryptoData.json()).then(cryptoData => {data = cryptoData;}).catch(err => console.log(err)); res.render('home', { cryptoData: data });

});

We declare the data variable, and when we get our crypto data back from the API, we set data to equal the crypto data, then we render our template with that data.

I don’t think so! fetch is asynchronous, so what would actually happen is:

We declare the data variable

variable We start the web request

We return our response

The web request completes, and we set data to equal the crypto data

If we were to structure it like the above snippet, our data would always be undefined in our template! We need to make sure we don’t send the response back until we have our data, and that means including the call to res.render() in the then method of the promise.

Promises can be chained using then to handle asynchronous actions easily. Each function that we pass into then isn’t executed until the previous one resolves. The catch method is executed if any of the then functions throw an error. We always want to make sure we handle errors, so the catch is required.

Note: The fetch API can do a lot of stuff involving web requests, but its default behavior is to make a simple GET request to the URL we pass in. That’s all we need for our example, but I wanted to explain clearly that all we are doing is making a GET request to the nexchange API, just like how a user will make a GET request to our app!

Before we move on, we should do another small round of refactoring to practice some Software Engineering principles. Functions should only really be concerned with one thing at a time, so if we find a function that is doing two totally different things, it means we should probably break it up into multiple pieces.

This is the idea of responsibility. Our route functions have the responsibility of sending back a response, but not fetching data from an API. The route function doesn’t care where our data is coming from, or how we get it, so we should break that responsibility out into it’s own function. Let’s refactor our route definition to look like this instead:



return fetch('

.then(cryptoData => cryptoData.json())

.then(cryptoData => {

return cryptoData.filter(crypto => crypto.code == code);

})

.catch(err => console.log(err));

} function getCryptos(code) {return fetch(' https://api.nexchange.io/en/api/v1/currency/' .then(cryptoData => cryptoData.json()).then(cryptoData => {return cryptoData.filter(crypto => crypto.code == code);}).catch(err => console.log(err)); app.get('/', (req, res) => {

const code = req.query.code; getCryptos(code)

.then(cryptoData => {

res.render('home', { cryptoData: cryptoData });

})

.catch(err => console.log(err))

});

Now we have a getCryptos() function that returns a promise ( fetch returns a promise, but so does then and catch . This is what allows you to chain them.) Now our route function can just call getCryptos() and it doesn’t need to worry about how we get the data. This way, if we decide to use a different API to get our crypto data later, we only have to change it in our getCryptos function.

Note: The main benefit of separating out code based on it’s responsibility is that it makes it more reusable. If we had another route that needed the crypto data, it too could just call getCryptos . In our small example, the benefit of the refactoring is negligible, but it will become necessary in larger apps. We just want to make sure you get some practice in sooner rather than later.

Oh, and one last note on promises. Whatever then returns is what the next then will get as an argument. This is what allows us to chain them. We usually use one call to then per transformation to the data. Let’s say we recieved some data from an API, then needed to sort them, filter them, and take the first piece, our promise code might look like this:

getAsyncData() // [3, 1, 2]

.then(sortData) // returns [1, 2, 3]

.then(filterData) // returns anything bigger than 1: [2, 3]

.then(takeFirstDatum); // returns 2

We could wrap all that logic into one function, where we sort and filter the data, then take the first piece, but when our then functions start to become a little more complicated, it’s nice to define the functions somewhere else, give them a clear name, and just pass the function reference into then , like I did above. It helps with readability, and makes the code look sort of like a recipe of how to convert the API data into what we need.

Tying It All Together

In the above code snippet, you’ll see we updated our call to res.render to include cryptoData in the context object, which used to be name . Now we can go ahead and update out template to show the crypto data we get back. But actually, before we do that, let’s save everything and restart the app.

When you navigate to the root route…

… you’ll see the app is broken, and we get this error message and stack trace to help figure out what’s wrong. Can you figure out what happened? The first line is telling us its a ReferenceError , and below the code snippet you’ll see the message is complaining that name is not defined . This is just because we aren’t passing a variable called “name” into the template, so it isn’t sure what to do! This is an easy fix, but we wanted you to see a proper error and stack trace. You’re going to want to get familiar seeing errors and stack traces, because no matter how talented you become, you’ll still see them everyday.

Anyway, let’s update our template to look for cryptoData instead of name . Since cryptoData is going to be an array, we will have to learn how to iterate over data with the ejs template syntax. Here is our new home.ejs file:

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<title>title</title>

</head>

<body>

<ul>

<% cryptoData.forEach(function(crypto) { %>

<li><%= crypto.code %> - <%= crypto.name %>: <% if (crypto.is_crypto) { %>

✅

<% } else { %>

❌

<% } %> </li>

<% }); %>

</ul>

</body>

</html>

While the syntax is a little messy, this is really simple logic that you’ll get in no time. All we are doing is calling forEach on our array of crypto data, printing out the code and name of the each one into an li (list) element, then returning a ✅ if the currency is a cryptocurrency, and a ❌ if it isn’t. That’s just a basic if statement disguised in weird ejs syntax, though. Remember, when calling forEach or map , or something similar, you pass in a function as an argument, and that function accepts just one piece of data. You get to decide what happens for each piece. For example:

const animals = ['dog', 'cat', 'moose']; function printAnimal(animal) {

console.log(animal);

} animals.forEach(printAnimal); // 'dog'

// 'cat'

// 'moose'

printAnimal gets run 3 times, because there are 3 items in animals . The first time, the animal argument is “dog”, the second time it’s “cat”, and finally it’s “moose”. We are doing the same thing with our crypto data, but instead of logging it to the console, we’re building HTML, which is way cooler!

Anyway, go ahead and save everything, then restart the app. Once you refresh the browser tab, you’ll see the final result!

And when we add a query parameter called “code” with one of the crypto codes…

… it shows us only that specific one!

Recap

This was a lot, but it helps set the basics of a backend app so you can start to explore your own ideas. We covered:

Installing dependencies

Defining routes in an Express app

Using a templating engine for HTML responses

Ensuring our code is clean and readable

Accessing the req object to read query parameters

object to read query parameters Making our own HTTP requests to get interesting data

Making our templates dynamic to display the data to a user

That’s nothing to sneeze at! But if you’re feeling really good about your programming skills, here are some ideas for you to extend your app: