Organize Your Node.js Code into Modules
As your Node.js application grows, you’ll want to collect your code into modules to better organize and manage it. Writing modular code also helps you reuse logic and functions without duplicating code you’ve already written. We will reuse the API requests and transform functions we wrote for the ETL pipeline earlier in our server by extracting them into a module.
By the end of this tutorial, you should be able to:
- Understand how to organize your Node.js code into modules
- Identify the benefits of creating modules to hold our code
This tutorial is part 3 of 7 tutorials that walk through using Express.js to create an API proxy server.
Goal
Create a module to hold the functions we’ll use for making API requests to the NASA Exoplanet API in our Node.js application.
Prerequisites
Watch: Organize Your Code into Modules
Overview
For our API proxy, we are reusing code that we wrote previously during the Extract Transform and Load to make API requests to the NASA Exoplanet API. We are going to create a module to hold the code for retrieving and transforming data from the Exoplanet API.
Creating modules helps organize your code, so related functionality is kept in a single place. We can avoid mixing together code which has different functions into one large file, or duplicating the code in different places. As we build the API proxy, we will be able to import the code to work with data from the Exoplanet API from this module.
If you want to learn more about the module system in Node.js, check out our tutorial, Overview: Node’s Module System.
We are going to place code we intend to reuse inside of a file that allows us to export the code at the end of the file. This lets us require
(import) the code elsewhere to be used again.
First let’s set up the dependencies we will need. The code we are using to request data from the Exoplanet API relies on request
and request-promise
as dependencies, so install them into your project:
npm i request request-promise
You’ll see a
npm WARN deprecated request
warning when installing this. That’s expected, the request package is deprecated but still functionally sound.
Create a directory called exoplanet in the root of your project, and then create an index.js file inside the exoplanet directory:
mkdir exoplanettouch exoplanet/index.js
The exoplanet/index.js file will hold the code we are going to export. Later, when importing the code with require
you’ll be able to pass just the path of the exoplanet directory and require will find the index.js file inside it automatically.
Passing the folder path to require will look like this:
require("./exoplanet");
To be clear, it’s not necessary to use the moduleName/index.js convention of creating modules in a directory. You could create a file called exoplanet.js at the root of the project and require it in the same way as above. We’ve used the directory approach mostly out of habit, but putting your modules into their own named files is completely valid as well.
Next, copy and paste the code we previously wrote for requesting and transforming planet records from the Exoplanet API, into the exoplanet/index.js file:
const rp = require("request-promise");
const EXO_API_URL = "https://exoplanetarchive.ipac.caltech.edu/cgi-bin/nstedAPI/nph-nstedAPI";
function getAllPlanets() { return rp({ uri: EXO_API_URL, method: "GET", qs: { table: "exoplanets", format: "json" }, json: true });}
function computeErrorThreshold(err1, err2) { if (err1 === null || err2 === null) { return null; } if (Math.abs(err1) === Math.abs(err2)) { return `±${Math.abs(err1)}`; } const max = Math.max(err1, err2); const min = Math.min(err1, err2); return `+${max}/${min}`;}
function transformOnePlanet(planet) { return { name: planet.pl_name, discoveryMethod: planet.pl_discmethod, facility: planet.pl_facility, neighbors: planet.pl_pnum, orbitsInDays: planet.pl_orbper, orbitsInDaysError: computeErrorThreshold( planet.pl_orbpererr1, planet.pl_orbpererr2 ), lastUpdate: planet.rowupdate, hostStar: planet.pl_hostname };}
We are also going to add another API call to get planets discovered since a particular year. Copy the following code into the file as well:
function getPlanetsDiscoveredSinceYear(year) { return rp({ uri: EXO_API_URL, qs: { table: "exoplanets", where: `pl_disc >= ${year}`, format: "json" }, json: true });}
To export the code from the module, we override the module.exports
object with a new object containing getAllPlanets
, getPlanetsDiscoveredSinceYear
, and transformOnePlanet
:
module.exports = { getAllPlanets, getPlanetsDiscoveredSinceYear, transformOnePlanet};
Once the code is assigned to module.exports
, it can be required in any other file in the project as it is needed using the require
function.
That’s it for this task. We will be using this code as we create the routes and handlers for the API proxy, but if you want to test that everything is working properly you can require the code in another file:
const { getPlanetsDiscoveredSinceYear, transformOnePlanet} = require("./exoplanet");
getPlanetsDiscoveredSinceYear(2020) .then(planets => planets.map(transformOnePlanet)) .then(console.log) .catch(console.err);
If you run this code, you should see something like the following logged to the console: exoplanets discovered since 2020:
[ { name: "HD 80653 b", discoveryMethod: "Transit", facility: "K2", neighbors: 1, orbitsInDays: 0.719573, orbitsInDaysError: "±0.000021", lastUpdate: "2020-01-30", hostStar: "HD 80653" }, { name: "TOI-813 b", discoveryMethod: "Transit", facility: "Transiting Exoplanet Survey Satellite (TESS)", neighbors: 1, orbitsInDays: 83.8911, orbitsInDaysError: "+0.0027/-0.0031", lastUpdate: "2020-01-30", hostStar: "TOI-813" }];
Recap
In this tutorial we created a module to hold the code we will use to interact with the NASA Exoplanet API as we build our API proxy. Putting this related code into a single module simplifies maintaining it in the future, and allows us to use the code wherever it is needed in our project by importing it using require
.
Keep going with the next tutorial in this set: Set up Routes for Your API in Node.js.
Further your understanding
- We are reusing code from another project, which means ultimately we might have the same code duplicated in different places. We could instead publish this code as a module to the NPM registry and use it as a dependency in both projects. Can you think of some scenarios where publishing your code and using it as a dependency would be useful? What about some scenarios where it wouldn’t be useful to consume a module as a dependency?
- If you did decide to publish this module publicly to NPM, how would you do that? What steps would you need to go through to publish the module?
Additional resources
- NASA Exoplanet API Documentation (exoplanetarchive.ipac.caltech.edu)