🚀 Open to New Opportunities! 💼

How to build movie rental app using NodeJs REST API with express and mongoDB - ES6 version. part-1

Introduction

Welcome to our comprehensive guide on building your very own movie rental app! In this tutorial, we will walk you through the process of creating a movie app from scratch. By the end of this guide, you will have the knowledge and skills to develop an app that allows movie owners to list their available titles and enables customers to easily rent and enjoy their favorite movies.

REST is an acronym for Representational State Transfer. REST follows some guidelines to facilitate communication between systems. In this post, we will learn how to build a movie rental app using REST API with NodeJs and MongoDB database, with all the code written in ES6. First, we will see how to set up a boilerplate project with the Express framework and configure our app to use ES6. After that, we will create an HTTP server and finally configure the NodeJS application to read data from the MongoDB database.

Prerequisites

Before we begin, make sure you have the following tools and technologies installed:

  • NodeJs: As an asynchronous event-driven JavaScript runtime, Node.js is designed to build scalable network applications.
  • Express Framework: Express is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications.
  • MongoDB: MongoDB is an open-source, cross-platform, and distributed document-based database designed for ease of application development and scaling. It is a NoSQL database developed by MongoDB Inc.
  • Babel: Babel is a toolchain that is mainly used to convert ECMAScript 2015+ code into a backwards compatible version of JavaScript in current and older browsers or environments.
  • VSCode: The editor we are using for the project. It's open-source and you can download it here.
  • Swagger: API documentation tool.
  • Postman: API Testing tool.
  • nodemon: To speed up the development process by automatically restarting the server when changes are detected.
  • dotenv: The dotenv package is a great way to keep passwords, API keys, and other sensitive data out of your code. It allows you to create environment variables in a .env file instead of putting them in your code.

If you are new to NodeJS and don't know how to build REST API with it, I would recommend going through this article, writing all the code by hand and avoiding copy-pasting to better understand the concepts.

Project Setup

Let's start by creating the folder structure of our project:

  1. Create a folder and call it Movio (or whatever name you prefer).
  2. Open that folder in the command line and execute the following commands to create the project structure:
mkdir src
cd src
mkdir config controllers documents middlewares model routes services utils validations
cd ..

After successful execution of the above commands, navigate back to the Movio directory by running the cd .. command.

Install package manager (NPM)

npm is a package manager which is going to help us manage dependencies. To start working with npm, you need to run:

npm init -y

We added the -y flag to accept all default options. For more explanation on npm init, you can read this article.

Now, let's install the packages we're going to use in the project. Run this command in your terminal:

npm install express mongoose dotenv joi @babel/core @babel/node @babel/preset-env morgan colors

Create a .env file in the root directory to hold our environment variables.

Babel Configuration

As mentioned earlier, Babel is a toolchain that helps us transpile our code from ECMAScript 2015+ into a backwards-compatible version of JavaScript. In this project, our code will be written in ES6.

Create a file .babelrc in the parent directory and add this code for configuration:

{
  "presets": ["@babel/preset-env"],
  "env": {
    "test": {
      "plugins": ["@babel/plugin-transform-modules-commonjs"]
    }
  }
}

After these steps, your project structure should look like this:

Project structure

Building the Application

Setting up Express

It's time for building! Navigate to the src folder and create the files app.js and server.js.

In app.js, add this code:

import express from 'express'
import morgan from 'morgan'

const app = express()

app.use(morgan('combined'))
app.use(express.json())

app.get('/', (req, res) => {
  return res.status(200).json({ message: 'Welcome to my Movio App' })
})

export default app

This sets up a basic Express application with Morgan for logging and a simple root route.

Configuring MongoDB Connection

Before we set up our Express server, let's first configure our app to work with MongoDB using Mongoose as the database engine.

Go into src/services and create a file called mongo.js. Add this code:

import mongoose from 'mongoose'
import color from 'colors'
import dotenv from 'dotenv'

dotenv.config()

const DB_URL = process.env.MONGO_URL

mongoose.connection.once('open', () => {
  console.log('Database Connected!'.blue.underline)
})

const mongoConnect = async () => {
  await mongoose.connect(DB_URL)
}

const mongoDisconnect = async () => {
  await mongoose.disconnect()
}

export { mongoConnect, mongoDisconnect }

This code sets up the MongoDB connection using Mongoose and provides functions to connect and disconnect from the database.

Setting up the Express Server

Now, let's set up our Express server. Go into server.js and add this code:

import http from 'http'
import dotenv from 'dotenv'
import { mongoConnect } from './services/mongo'
import app from './app'

dotenv.config()

const PORT = process.env.PORT || 3000

const server = http.createServer(app)

const startServer = async () => {
  await mongoConnect()
  server.listen(PORT, () => {
    console.log(`Server is running on port ${PORT}`)
  })
}

startServer()

This code creates an HTTP server using our Express app, connects to MongoDB, and starts the server listening on the specified port.

Creating the Genre Model

Now let's start building our Movio app. When it comes to software building, developers have different approaches, but in my opinion, the best approach is to first design your database model.

Go to the model folder and create a file called genre.js. Add this code:

import mongoose from 'mongoose'

const genreSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true,
    minlength: 5,
    maxlength: 50,
  },
})

const Genre = mongoose.model('Genre', genreSchema)

export { Genre }

This creates a simple Mongoose model for movie genres.

Implementing the Genre Controller

Next, let's create a controller for our genre model. Add a file in the controller folder called genre.controller.js and insert this code:

import { Genre } from '../model/genre'

const addGenre = async (req, res) => {
  try {
    const { name } = req.body
    let genre = new Genre({
      name,
    })
    await genre.save()

    return res.status(201).json({ message: 'Genre created successful', genre })
  } catch (err) {
    return res.status(500).json({ error: err, message: 'Server error' })
  }
}

export { addGenre }

This controller handles the creation of new genres.

Setting up Routes

Let's connect this controller with our routes. Go into the routes folder and create another folder inside called api. This will contain all files for our endpoints. Create a file inside the api folder called genre.routes.js. All routes related to genre are going to be held by this file. Add this code:

import { Router } from 'express'
import { addGenre } from '../../controllers/genre.controller'

const route = Router()

route.post('/', addGenre)

export default route

Now we have routes for adding genres using the POST method. The next step is to give these routes specific endpoints. Create a file index.js in the routes folder which is going to provide endpoints for all our routes. Insert this code:

import { Router } from 'express'
import genre from './api/genre.routes'

const routes = Router()

routes.use('/genre', genre)
export default routes

Updating the Main App

We're well on our way to completing these endpoints. Now we have everything; the only thing remaining is to add the app base URL.

Go into app.js and update it by providing a base URL for our app. Here's the updated app.js:

import express from 'express'
import morgan from 'morgan'
import allRoutes from './routes/index'

const app = express()

app.use(morgan('combined'))
app.use(express.json())

app.use('/api/v1', allRoutes) // create the base url
app.get('/', (req, res) => {
  return res.status(200).json({ message: 'Welcome to my Movio App' })
})

export default app

Documenting the API with Swagger

Now that our genre endpoint is working correctly, let's document our API using Swagger.

First, we need to install the Swagger package which is going to help us configure our app. Run this command in your terminal:

npm install swagger-jsdoc swagger-ui-express

After your package is installed, let's create a file that will hold our endpoints documentation. In the src directory, create a file called swagger.js and add this code:

import dotenv from 'dotenv/config'
import { addGenre } from './documents/genre.docs'

export const swaggerDocument = {
  openapi: '3.0.1',
  info: {
    version: '1.0.0',
    title: 'Movio APIs Document',
    description:
      'Movio: an movie app for renting and listing Movie in the store',
    termsOfService: '',
    contact: {
      name: 'Leandre', //add your name
      email: 'myemail@gmail.com', //replace this with your email
      url: 'https://leandredev.netlify.app/', //add your website link
    },
  },
  servers: [
    {
      url: `http://localhost:${process.env.PORT}`, // url
      description: 'Local server', //
    },
    {
      url: 'https://movio-api.onrender.com/', // url hosted version
      description: 'Hosted version', // name
    },
  ],
  components: {
    securitySchemes: {
      bearerAuth: {
        type: 'apiKey',
        name: 'Authorization',
        scheme: 'bearer',
        in: 'header',
      },
    },
  },
  paths: {
    '/api/v1/genre': {
      post: addGenre,
    },
  },
}

Now, let's document our endpoints. Create a file in the document directory and call it genre.docs.js. This will hold all documentation endpoints for the Genre API. Add this code:

export const addGenre = {
  tags: ['Genre'],
  summary: 'Create genre',
  description: 'Create a movie genre',
  parameters: [],
  requestBody: {
    required: true,
    content: {
      'application/json': {
        schema: {
          type: 'object',
          properties: {
            name: {
              type: 'string',
              required: true,
            },
          },
          example: {
            name: 'Romantic',
          },
        },
      },
    },
  },
  consumes: ['application/json'],
  responses: {
    201: {
      description: 'Genre added successfull',
    },
    500: {
      description: 'Server error',
    },
  },
}

After completing this task, the final step is to configure our Swagger in the main app.js. Update this file with this code:

import express from 'express'
import morgan from 'morgan'
import swaggerUi from 'swagger-ui-express'
import allRoutes from './routes/index'
import { swaggerDocument } from './swagger'

const app = express()

app.use(morgan('combined'))
app.use(express.json())

app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument))
app.use('/api/v1', allRoutes)
app.get('/', (req, res) => {
  return res.status(200).json({ message: 'Welcome to my Movio App' })
})

export default app

Testing the Application

To test this, navigate to http://localhost:<PORT>/api-docs in your browser. You should see the Swagger UI with your documented API.

Conclusion

We have seen how to set up MongoDB and Babel and configure it in a NodeJS API written in ES6. We've also created a basic Genre model, implemented a POST endpoint for creating new genres, and documented our API using Swagger.

Practice makes perfect! As an exercise, try to build a GET endpoint for retrieving all genres and document it with Swagger. You'll find the solution in part 2, which I will release soon.

In future posts, we will see how to build more endpoints for genres and customers, implement PUT and DELETE operations, and add more advanced features to our movie rental app.

Remember, if you encounter any errors while following this tutorial, feel free to post them in the comments, and I'll do my best to help you find a solution.