Having been immersed in NodeJS and React over the last few years, it came to my attention that I should share the basics of a backend JSON API structure. To start, we can go over what is required to install and begin creating our API, what an API even is, and how to implement it. First and foremost, we need to install NodeJS and Node Package Manager (NPM). You can also use Yarn for package installation and management.

Prerequisites

I installed NodeJS with the installer from the website, then I had installed yarn via NPM following the setup to enable settings and initialize future packages. Either may be used. Some package combinations required me to utilize yarn for efficiency so it all depends on what you need. For this purpose, we will use NPM. A basic code editor is required as well and for this, I use Visual Studio Code to organize workspaces, debug projects, and version control with Git.

JavaScript and Command Lines

Before you dive into to heart of the tutorial, you should familiarize yourself with basic JavaScript concepts like the arrow function expression and asynchronous programming with async await. You also need to familiarize yourself with the integrated Terminal in VS Code, or more specifically the command line and the interfaces used with other tools, as most of the setup process will be done using the command line.

APIs

What is an API? Simply put, API (Application Programming Interface) is like an intermediary between multiple applications that allows them to transfer information/data to and from each other. RESTful API (Representational state transfer) is one of many guidelines for APIs and should be something every frontend developer should know.

NodeJS

NodeJS is an asynchronous event-driven JavaScript runtime, that is leveraged to design and build scalable network applications.

Express

It is a popular module framework for NodeJS, allowing frontend developers to make web applications and API building and designing quick and easy. From their own website, Express is a minimal and flexible NodeJS web application framework that provides a robust set of features for web and mobile applications.

Axios

A very handy and popular library used to make promise based HTTP requests. On the server-side it uses the native NodeJS http module, while on the client-side, or browser, it uses XMLHttpRequests. You can read more about Axios vs. Fetch to understand more about using this package. Considering Fetch works only within the browser, we must use Axios with Express on the backend.

Installation

We start by installing NodeJS and NPM with the instructions above and initialize our project. Afterwards, we open any tool like Git Bash or the the Terminal within VS Code and install the packages via NPM or Yarn. Following the initialization and installation, we have some dev dependencies we can capitalize on to format our code and help us eliminate any possibility of bugs or errors along the way. Prettier and ESLint are the preferred tools for reviewing and reporting any issues within the code. Nodemon is a utility tool that will monitor for any changes made in your source folder and automatically restart your server.

// NPM Installation
npm init
npm i axios express
npm i --save-dev eslint nodemon prettier
// Alternative Yarn Installation
yarn init
yarn add axios express
yarn add --dev eslint nodemon prettier

Now we can initialize ESLint for our project’s purpose.

npm init @eslint/config
✔ How would you like to use ESLint? · problems ✔ What type of modules does your project use? · commonjs ✔ Which framework does your project use? · react ✔ Does your project use TypeScript? · No ✔ Where does your code run? · browser ✔ What format do you want your config file to be in? · JavaScript eslint-plugin-react@latest ? Would you like to install them now with npm? › Yes

We can now update the package.json with the following scripts to run our application and streamline the process.

"scripts": {
"format": "prettier --write \"src/**/*.{js,json}\"",
"lint": "eslint src/**",
"start":"nodemon src/app.js"
},

Hello, World!

Here is where we begin the process of coding our application. First, we need to create an HTTP Server that will listen on port 3000. We’ll send a basic response to the browser with a GET request. There is also an important note to make on scalability and readability with a proper folder structure to organize our codebase. Typically, we place our source code within /src directly in the root folder of the project and create app.js within it to be our main file for launching the application.

const express = require('express')
const app = express()
app.get('/', (req, res) => {
res.send('Hello, World!')
})
app.listen(3000, () => {
console.log('The server is running on port 3000.')
})

A call to the root directory — or main route (/) — will respond with the “Hello, World!” message. Starting the server with the following command will launch our browser with localhost:3000 and our generic response should load.

npm run start

Congratulations, you’ve just created and launched your first API and server. Now it’s time to implement some best practices for different environments.

Configuration and Best Practices

You can see more about setting up environment variables, but for this project the setup below is all that is needed for this API project. In one way or another, ENV variables can be added and for this project, we will utilize cross-env to setup our environments and configuration file. We can simply name config.json and save the contents for our environment variables.

// Mac OS
export NODE_ENV=development
 
// Windows
SET NODE_ENV=development
 
// via PowerShell may require this
$env:NODE_ENV="development"
 
// Install cross-env and initialize
npm i --save-dev cross-env
cross-env NODE_ENV=development
// Configuration file (config.json)
{
"development": {
"port": 3000
},
"test": {
"port": 4000
},
"production": {
"port": 5000
}
}

Now we can update our scripts in package.json and apply these updates to our app.js file.

// Updated scripts in package.json
"scripts": {
... // previous scripts may remain
"start:development": "cross-env NODE_ENV=development nodemon src/app.js",
"start:production": "cross-env NODE_ENV=production nodemon src/app.js"
},
// Updated app.js
const express = require('express')
const app = express()
const config = require('./config/config.json')
const env = process.env.NODE_ENV
const configuration = config[env]
app.get('/', (req, res) => {
res.send('Hello, World!')
})
app.listen(configuration.port, () => {
console.log(`The server is running on port ${configuration.port}.`)
})

The following command will now run from the development server as per the configuration file and start listening on port 3000.

npm run start:develoment

With the basic structure created, we can now divide the server from the application itself. Start by creating a new file within the source directory and call it server.js where we can store the server portion of the code.

// Updated app.js
const express = require('express')
const app = express()
const config = require('./config/config.json')
const env = process.env.NODE_ENV
const configuration = config[env]
app.get('/', (req, res) => {
res.send('Hello, World!')
})
module.exports = app
// New server.js
const app = require('./app')
const config = require('./config/config.json')
const env = process.env.NODE_ENV
const configuration = config[env]
app.listen(configuration.port, () => {
console.log(`The server is running on port ${configuration.port}.`)
})

We can also update the scripts to include the server.js file we recently created.

// Changes to the start scripts in package.json
"scripts": {
"start:development": "cross-env NODE_ENV=development nodemon src/server.js",
"start:production": "cross-env NODE_ENV=production nodemon src/server.js"
},

Routes

Routes are the different paths that follow the root domain, like ‘/’ or ‘/random. "Routes” are extensions of the main application’s URL that is used to forward the supported requests to the appropriate controller functions. Controller functions get the requested data from the source and return it to the user to view in the browser.

Let’s create two new files index.js and activity.js within a new directory called routes. Next we can populate both files with a similar structure as above. It may seem redundant, but this will help in the scalability of the project. As it grows, it will be easier to find and edit portions of the application based on how this has been setup from the beginning.

// index.js
const express = require('express')
const router = express.Router()
const activity = require('./activity')
router.get('/random', activity)
module.exports = router
// activity.js
const express = require('express')
const axios = require('axios')
 
let getActivity = async () => {
let response = await axios(`https://www.boredapi.com/api/activity/`)
return response
}
 
module.exports = async (req, res) => {
let result = await getActivity()
res.send(result.data.activity)
}

Finally, let us connect all the pieces into one functioning application. The last step is to updated the app.js file with our latest additions. Here, we used app.use to mount the routes via middleware that we required from the routes folder.

// Integrated updates in app.js
const express = require('express')
const app = express()
const middleware = require('../src/routes')
const app.use('/random', middleware)
app.get('/', (req, res) => {
res.send('Hello, World!')
})
module.exports = app
// Successful URL for the API
http://localhost:3000/random/activity

And with all of that complete, your first simple JSON application should be ready to go. Happy coding with this scalable tutorial.