Skip to main content
Node.js APIs Tutorial
CHAPTER 11 Beginner

Connecting APIs with MySQL and MongoDB

Updated: May 14, 2026
35 min read

# CHAPTER 11

Connecting APIs with MySQL and MongoDB

1. Introduction

A REST API without a database is just an expensive calculator; it cannot remember anything. To persist data permanently, Node.js must connect to an external database. Node.js is uniquely versatile because it works beautifully with both Relational databases (MySQL) and NoSQL databases (MongoDB). In this chapter, we will learn how to connect an Express API to a database, execute queries asynchronously, and return the real data as JSON.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Connect an Express API to a MySQL database using the mysql2 package.
  • Connect an Express API to MongoDB using the mongoose package.
  • Execute basic database queries asynchronously using async/await.
  • Understand the difference between relational and document databases in Node.

3. Beginner-Friendly Explanation

Imagine your Node.js application is a factory manager.
  • MySQL is an Excel Spreadsheet. Data must fit perfectly into rows and columns. If you try to put a shoe into the "Hats" column, the spreadsheet rejects it.
  • MongoDB is a Filing Cabinet. Data is stored in folders (Documents) as pure JSON objects. You can throw a shoe, a hat, and a receipt into the same folder, and MongoDB doesn't care. It is highly flexible.

Because Node.js naturally speaks JSON, it is best friends with MongoDB. However, for enterprise systems that require strict financial records, Node.js works perfectly with MySQL.

4. Database 1: MySQL Integration

To connect to MySQL, we use the mysql2 package because it natively supports modern JavaScript Promises (allowing us to use async/await).

Step 1: Install

bash
1
npm install mysql2

Step 2: Database Configuration (config/db.js)

javascript
1234567891011
const mysql = require('mysql2/promise');

// Create a connection pool (better for performance than a single connection)
const pool = mysql.createPool({
    host: 'localhost',
    user: 'root',
    password: 'password123',
    database: 'my_api_db'
});

module.exports = pool;

Step 3: The MySQL Controller

javascript
12345678910111213
const db = require('../config/db');

const getUsers = async (req, res) => {
    try {
        // Execute raw SQL asynchronously
        const [rows] = await db.query('SELECT * FROM users');
        
        res.status(200).json({ status: 'success', data: rows });
    } catch (error) {
        // If the database is down, return a 500 Server Error
        res.status(500).json({ error: error.message });
    }
};

5. Database 2: MongoDB Integration (Using Mongoose)

Writing raw MongoDB queries is tedious. Instead, we use an ODM (Object Data Modeling) library called Mongoose. Mongoose acts as a translator, allowing us to interact with MongoDB using JavaScript objects.

Step 1: Install

bash
1
npm install mongoose

Step 2: Database Configuration (config/db.js)

javascript
1234567891011121314
const mongoose = require('mongoose');

const connectDB = async () => {
    try {
        // Connect to local MongoDB instance
        await mongoose.connect('mongodb://localhost:27017/my_api_db');
        console.log("MongoDB Connected Successfully");
    } catch (error) {
        console.error("MongoDB Connection Failed:", error);
        process.exit(1); // Kill the server if DB fails
    }
};

module.exports = connectDB;

6. Defining a Mongoose Model

MongoDB is schema-less by nature. Mongoose forces a schema onto it so our API data stays predictable.

models/User.js

javascript
1234567891011
const mongoose = require('mongoose');

// Define the blueprint for a User
const userSchema = new mongoose.Schema({
    name: { type: String, required: true },
    email: { type: String, required: true, unique: true },
    age: { type: Number, default: 18 }
});

// Compile it into a Model and export it
module.exports = mongoose.model('User', userSchema);

7. The MongoDB Controller

Notice how much cleaner Mongoose is compared to raw MySQL strings!
javascript
12345678910111213141516171819
const User = require('../models/User');

const createUser = async (req, res) => {
    try {
        // 1. Create a new User object from the Request Body
        const newUser = new User({
            name: req.body.name,
            email: req.body.email,
            age: req.body.age
        });

        // 2. Save it to MongoDB
        await newUser.save();

        res.status(201).json({ status: 'success', data: newUser });
    } catch (error) {
        res.status(400).json({ error: error.message });
    }
};

8. Backend Workflow: Connection Timing

Where do you connect to the database? You MUST connect to the database *before* you turn on the Express server. If your server is listening for traffic, but the database connection hasn't finished, the first 100 users will crash the app.

In app.js:

javascript
123456789
const connectDB = require('./config/db');

// Connect to DB FIRST
connectDB().then(() => {
    // Only start listening for traffic if DB is successful
    app.listen(3000, () => {
        console.log("Server running on port 3000");
    });
});

9. Best Practices

  • Never Hardcode Credentials: Your database password (root123) should NEVER be typed directly into your JavaScript files. You must use a .env file (via the dotenv package) to hide credentials from GitHub. We will cover this heavily in the deployment and security chapters.

10. Common Mistakes

  • Forgetting await: If you write const users = User.find(); without await, the users variable will not contain the database rows; it will contain a pending Promise. When you send it via res.json(), the user will receive a bizarre, empty object. Always await your database queries!

11. Exercises

  1. 1. Compare the process of querying a database using raw SQL (via mysql2) versus using an ODM like Mongoose. What are the advantages of using Mongoose?

12. Coding Challenges

  • Challenge: Using Mongoose syntax, write the controller logic to find a single user by their ID, assuming the ID is passed in the URL parameters. Use the User.findById() method.

13. MCQs with Answers

Question 1

When building an Express API with MongoDB, what is the purpose of the mongoose package?

Question 2

Why is it standard practice to establish the database connection *before* calling app.listen() in your app.js file?

14. Interview Questions

  • Q: Explain why Node.js and MongoDB are frequently paired together (The MEAN/MERN stack). What is the underlying data format they share?
  • Q: Describe how you handle asynchronous errors in an Express controller that is querying a database. Why is the try/catch block critical?

15. FAQs

Q: Which database should I choose for my project? A: Use MySQL/PostgreSQL if your data is highly relational and structured (e.g., a Banking app where Accounts, Transactions, and Users must be strictly linked). Use MongoDB if your data is flexible, unstructured, or rapidly changing (e.g., a Social Media feed, IoT sensor data).

16. Summary

In Chapter 11, we gave our API a memory. We explored the two dominant database paradigms: Relational (MySQL) and NoSQL (MongoDB). By utilizing the mysql2 and mongoose packages, we executed asynchronous queries to retrieve, create, and format real, persistent data into JSON. Finally, we learned the critical architectural rule of initiating database connections prior to opening the server to internet traffic.

17. Next Chapter Recommendation

Anyone can currently hit our endpoints and modify our database. We need to lock the doors. Proceed to Chapter 12: Authentication and JWT Tokens.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·