Building a Blog API with Node.js: Introduction and Setting up the Server (Part 1)

Introduction

In this series, we'll be building a simple blog API using Node.js. If you're not familiar with what an API is, it stands for "Application Programming Interface" and it allows different software systems to communicate with each other. In this case, our blog API will allow us to create, read, update, and delete blog posts, as well as manage user authentication.

Why build a blog API with Node.js? Node.js is a popular, open-source runtime environment for executing JavaScript code outside of a browser. It has a large, active community of developers and a wealth of libraries and frameworks that make it easy to build scalable, high-performance web applications.

In this first article, we'll cover the initial steps of setting up our development environment, creating a new project and setting up our server. Let's get started!

Prerequisites

Here's what we'll need:

  • Node.js: You can download the latest version of Node.js from the official website and follow the installation instructions. This will also install the Node.js package manager (npm), which we'll use to install additional packages.

  • MongoDB: We'll be using a MongoDB database to store our data. You can follow the installation instructions on the official website.

  • A code editor: You can use any code editor that you prefer, such as Visual Studio Code, Sublime Text, or Atom.

  • A terminal: We'll be using the integrated VS code terminal to run commands and interact with our project, but you can use your preferred terminal.

  • A basic understanding of JavaScript, APIs, databases and other web development concepts. If you're new to these topics, it might be helpful to brush up on your knowledge before diving into this tutorial.

Setting up the Development Environment

  1. To create a new project, open up your terminal and navigate to the directory where you want to create your project. Then, run the following command:

     npm init -y
    

    This will create a package.json file in your project directory, which is used to manage dependencies and scripts for your project. The -y flag accepts all the default options, so you don't have to manually enter them.

  2. Next, run the following command to install these dependencies:

     npm install --save express dotenv cors express-rate-limit helmet express-fileupload
    

File Structure

Now that we have our dependencies installed, let's create the file structure for our project. Create the following directories and files in your project directory:

  • /src: This is the main directory for our project. It will contain all the source code for our application.

  • /src/authentication: This directory will contain the code related to user authentication, such as password hashing and JWT generation.

  • /src/config: This directory will contain configuration files for our application, such as the database connection string and server port number.

  • /src/controllers: This directory will contain the code for the controllers of our API. Controllers handle incoming requests and send responses to the client.

  • /src/database: This directory will contain the code for connecting to and interacting with the database.

  • /src/loggers: This directory will contain the code for logging events in our application.

  • /src/models: This directory will contain the code for the database models of our application. Models represent the data stored in the database and provide an interface for interacting with that data.

  • /src/routes: This directory will contain the code for the API routes. Routes define the endpoints of our API and specify the HTTP methods (e.g., GET, POST) that can be used to access them.

  • /src/services: This directory will contain any service objects or utility functions that are used throughout our application.

  • /src/validators: This directory will contain the code for validating input data.

  • app.js: This file will contain the middleware and routers for the server.

  • index.js: This is the entry point for our application. It will contain the code for starting the server and connecting to the database.

  • package.json: This file contains metadata for the API. The start script should be: "start": "node index.js".

Setting Up Environment Variables

Let's set up the environment variables we'll need for this project. As we build, it will become clear why each variable is needed.

Avoid exposing your API secrets, as it is a security risk. If you're using version control, you can set up a config file that you can push without exposing any secrets, or you may create a .env.example showing the variable names only, with no values.

  1. Create an index.js file in /src/config:

     require("dotenv").config();
    
     module.exports = {
         PORT: process.env.PORT,
         MONGODB_CONNECTION_URL: process.env.MONGODB_CONNECTION_URL,
         JWT_SECRET: process.env.JWT_SECRET,
         CLOUDINARY_URL: process.env.CLOUDINARY_URL,
     };
    
  2. In the root directory, create a .env file. We'll update the values as we build:

     PORT=5000
     MONGODB_CONNECTION_URL=
     JWT_SECRET=
     CLOUDINARY_URL=
    

Setting up the server

  1. In the app.js file, add the following code:

     const express = require("express");
     const rateLimit = require("express-rate-limit");
     const helmet = require("helmet");
     const cors = require("cors");
    
     const CONFIG = require("./src/config");
    
     const app = express();
    
     app.use(cors());
    
     const limiter = rateLimit({
         windowMs: 15 * 60 * 1000,
         max: 100,
         standardHeaders: true,
         legacyHeaders: true,
         message: "Too many requests, please try again after 15 minutes",
     });
     app.use(limiter);
     app.use(helmet());
     app.use(express.json());
     app.use(express.urlencoded({ extended: true }));
     app.use(
       fileUpload({
         createParentPath: true,
         useTempFiles: true,
         tempFileDir: "/tmp/",
       })
     );
    
     app.get("/", (req, res) => {
         return res.json({ status: true });
     });
    
     // 404 error handler
     app.use("*", (req, res) => {
         return res.status(404).json({ message: "Route not found" });
     });
    
     // Error Handler
     app.use(function (err, req, res, next) {
         console.log(err.message);
         res.status(err.status || 500).send("Oops, something failed");
     });
    
     module.exports = app;
    

    We've set up the following middleware:

    cors allows cross-origin resource sharing, which means that our API can be accessed from a different domain.

    Following that, we have a rate-limiting middleware that limits the number of requests a user can make within a certain period. This helps protect against malicious users trying to overwhelm the server with requests:

     const limiter = rateLimit({
         windowMs: 15 * 60 * 1000,
         max: 100,
         standardHeaders: true,
         legacyHeaders: true,
         message: "Too many requests, please try again after 15 minutes",
     });
     app.use(limiter);
    

    We also have the helmet middleware, which helps secure the API by setting various HTTP headers.

    Then, we have the following middleware which allows the API to process JSON and URL-encoded data in the body of requests:

     app.use(express.json()); 
     app.use(express.urlencoded({ extended: true }));
    

    Finally, we have the fileUpload middleware, which allows the API to handle file uploads:

     app.use(fileUpload({ 
         createParentPath: true, 
         useTempFiles: true, 
         tempFileDir: "/tmp/", 
     }));
    
  2. In the index.js file, add the following code:

     const app = require("./app");
    
     const CONFIG = require("./src/config");
    
     app.listen(CONFIG.PORT, () => {
         console.log(`server listening on port ${CONFIG.PORT}`);
     });
    

Now we're ready to start coding the individual components of our blog API. In the next article, we'll begin with the database models and establish a connection to the database. Stay tuned!