How To Build a Simple NodeJS Cryptocurrency App

James Quinlan
thebit
Published in
15 min readSep 4, 2018

The Tooling

For this tutorial, we will focus on using Express, which is a micro-framework for server-side Javascript. It’s built on top of Node, which is just a JS runtime that runs outside of the browser (like on watches, robots, and servers, as previously mentioned).

Note: Before continuing, you’ll want to know the basics of setting up a new JS app with NPM or Yarn (don’t worry, for this project it will be easy). You’ll also need to make sure you have Node installed on your machine. If you don’t know how to do that, please see our tutorial on using NPM.

Create a new directory for this project, and make sure to npm init inside of it so we can start keeping track of our packages. After that, we can install express:

npm install --save express

For now, that’s all we’ll need, but it’s worth knowing that the server-side JS ecosystem is diverse and expansive. This means that there are thousands of packages you could add to your application in conjunction with express to handle authentication, middleware, file management, database connections, etc. A fully-featured Javascript backend app is likely to contain an assortment of packages all working cohesively. This is what I meant earlier when I called express a micro-framework: it only handles a small amount of functionality for us, the rest will come from other packages that aren’t affiliated with express at all! Neat.

Hello, Backend World!

Alright, let’s take a look at the official Hello World example that is provided in the express docs:

const express = require('express');
const app = express();
app.get('/', (req, res) => res.send('Hello World!'));app.listen(3000, () => {
console.log('Example app listening on port 3000!');
});

We can walk through this a little bit so we get a feel for the basics. Go ahead and create a file called index.js in your project directory and copy the above script into it. The first line is simple enough, as we’re just importing our dependency using node's require syntax. Then, we go ahead and create our app object by calling express().

After that, we call app.get() and pass it two arguments: a string which corresponds to a URL, and a function that determines what code should run when a user makes a request to that URL. In this case, our route is just /which is referred to as the root. The function will always accept two arguments, the request object, then the response object. The request is the HTTP Request that our app is receiving, and it contains a plethora of information, like data that the user is trying to upload, or information we might need to authenticate the user. This is the basic structure of a simple backend API: a user makes a request to a certain route of our app, and we run code to determine what to send back to the user. We will cover this in more detail later.

Once we have defined a few routes, our script calls app.listen() which also takes two arguments: the port on which we should listen for requests, and a function to execute once this process is done. A function that is called at the end of a process is called a callback.

Go ahead and start your app by running node index.js in the terminal. Make sure you run that in the directory that contains index.js otherwise you’ll get an error and nothing cool will happen. If it all works, you should see “Example app listening on port 3000!” logged into the console. If you don’t see that, try to see what error appears. You most likely aren’t in the correct directory, or you didn’t install the express dependency yet.

Now that the app is running, you can navigate to http://localhost:3000 in your browser, and you’ll see “Hello World!” on the page. Woo!

Hello World, v2.0

Before we move on to extending the functionality of our app, let’s do a bit of refactoring to practice some Software Engineering principles, the most important of which will be ensuring that our code is readable and self-documenting.

Step one will be moving the callback function that we pass into our route, at app.get(). Let’s change it to look like this:

function handleIndexRequest(req, res) {
res.send('Hello World!');
}
app.get('/', handleIndexRequest);

This is a trivial example, but it will help us to get into the habit of ensuring that we name our functions, classes, and variables based on what they do. This way someone else, or even the original author, can look at the code and quickly get an idea of what precisely is happening. As they say, software engineering is just coding in a social context, so we always want to make sure our code is clear and readable for our coworkers who might later need to work on what we’ve written.

Right now, our only defined route is using the get method on our app object (Remember, a method is just a function that’s attached to an object or class). This means that this route will only respond to GET requests, and not POST, PUT or DELETE requests. A GET request is used to signify that a user wants to simply retrieve something from the server or application. When navigating to a URL in our browser’s address bar, such as when we had to visit http://localhost:3000, a GET request is made to that URL, and the browser will automatically display the response.

So now that we have a very basic app running, let’s extend it in two ways: adding a templating engine, and interfacing with a 3rd party API. This is going to require us to install some new packages, so let’s take these one at a time.

Adding a Templating Engine

Right now, our app will only return a basic response containing some text when a user makes a GET request to the root of our application. One of the more common response types, however, is with an HTML page. In order to send HTML pages from our app, we need to teach it how.

First, let’s install something called ejs, which allows us to build HTML files with Javascript on the server.

npm install ejs --save

Nifty. Now that we have our dependency installed, let’s tell our app to use it.

app.set('view engine', 'ejs');

Now that our app can technically understand HTML templates, let’s create some new directories to store them. In the same directory as your index.jsfile, create a directory called views. Inside that, create a file calledhome.ejs. Notice the file extension, .ejs, which isn’t the normal .html extension we would expect to see. This is just an idiosyncrasy of ejs, so that the package knows which files it should look at when it comes times to create a new HTML file for a user.

This is what our file structure should look like at this point:

Let’s add some basic HTML to our home.ejs file, now:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Is It Crypto</title>
</head>
<body>
<h1>I think our template is working.</h1>
</body>
</html>

That should do for now, we can make it cool and dynamic later. Let’s go ahead and test it by updating our index route function to send this HTML back instead of our “Hello World!” text. express has a variety of response types, such as JSON and HTML, which are probably the most common. We can use the render method on the res object (this is the response that we will send the user) by passing it the template to use. Update the handleIndexRequestfunction to look like the following snippet:

function handleIndexRequest(req, res) {
res.render('home');
}

Note: The render method will automatically look in our views directory for the template we pass in as an argument (in this case home.ejs), so we don’t need to pass in the full relative path the template. This is something you would probably only know by reading the documentation for express. RTFM!

Now go back to your terminal, and kill the app if it’s still running by hitting Ctrl + C on the keyboard (this is the command to terminate a process). Then restart the app with node index.js again. When you refresh the browser, you should see some nice big text saying “I think our template is working” staring back at you! If you don’t see that, make sure all your files are saved, and that you installed the ejs dependency.

It’s not much yet, but it’s progress!

But ejs lets us do something even cooler, which is make our views dynamic. When you visit YouTube, you don’t always see the same videos on the Home page, as these things change. We don’t want to have to manually build out all of our HTML pages, we want to teach our app how to build pages based on our data.

Now let’s make our template dynamic by showing something different depending on how where we navigate to in our app.

There are a fews way that our routes can contain dynamic information. We can store information in something called a query parameter. Query parameters are the things you see in a URL after the ?, if there is one. An example is something like ui/bento.html?reason=st where the parameter reason has a value of st. We can access these values in our route function as a part of the req object, with something like this:

const reason = req.query.reason; // this would equal 'st'

Easy! express manually reads the URL for us before we get it and organizes it into a neat package for us, so we can just check the req.query object to see what query parameters were sent. Adding query parameters to a URL doesn’t make it a new route though, so if we were to make a GET request to http://localhost:3000?foo=bar then our route definition for the application root will still fire. So, let’s go ahead and update our route function to look for a query parameter!

function handleIndexRequest(req, res) {
const name = req.query.name || 'Stranger';
res.render('home' { name: name });
}

Alright, we’ve got a couple new things in here, don’t we? We define a variable called name and set it to equal the “name” query parament or the string value of “Stranger”. This syntax just means that if the first part of the conditional is false, the second part will be used, so if we don’t have a query parameter called “name” in the URL, this name variable will be set to “Stranger” instead. Then below that, in the call to render you see we added a new object as a second argument. This is known as context, and it’s basically data we want to inject into our template. Right now we only need to worry about injecting the name variable, so we can pass just that in.

Since that information is being sent to our template, courtesy of the rendermethod, let’s update our template to display it. Update the line with the <h1>to the following:

<h1>I think our template is working, <%= name %>!</h1>

This new syntax, the <%= %> stuff, is all specific to ejs, not Node or Javascript or anything. But now if you restart your app and refresh your browser tab, you’ll see this!

And if you add a query parameter called “name”…

How slick is that! Now our app can build our views based on our data. And this is just a trivial example, ejs can do a lot more if you want to read the docs and really start exploring. Now, what if we had more interesting data…

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. 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;
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. For example, why wouldn’t this code work?

app.get('/', (req, res) => {
let data;
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
  • 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.

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:

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 getCryptosfunction.

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 received 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.

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
  • 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:

  • Add CSS and improve the layout
  • Use a different API
  • Define a new route and show different data

--

--