Express remains one of the most popular backend frameworks in the JavaScript ecosystem because it’s minimal, flexible, and easy to reason about. When you pair it with ES6 syntax and MongoDB, you get a lightweight but powerful stack that’s perfect for APIs, side projects, MVPs, and even production services.

In this post, we’ll build a simple Blog REST API using:

We’ll focus on clarity, clean structure, and real-world patterns — not just getting something to work, but building something you’d actually want to maintain.


What We’re Building

By the end of this tutorial, we’ll have a REST API that supports:

In short: full CRUD functionality for a blog.

This API will serve as a solid foundation you can later extend with:


Why Express + ES6 + MongoDB?

Before jumping into code, let’s talk about why this stack works so well.

Express

Express gives you:

It doesn’t force architectural decisions — which is both a strength and a responsibility.

ES6 Modules

Using import and export:

MongoDB

MongoDB is a great fit for blog content because:


Project Setup

Initialize the project

mkdir blog-api
cd blog-api
npm init -y

Install dependencies:

npm install express mongoose
npm install --save-dev nodemon

Enable ES6 Modules

In package.json, add:

{
  "type": "module"
}

This tells Node.js to treat .js files as ES modules, allowing us to use import and export.


Project Structure

A clean structure makes even small projects easier to extend.

src/
  server.js
  config/
    database.js
  models/
    Post.js
  routes/
    postRoutes.js
  controllers/
    postController.js

Each layer has a single responsibility:


Connecting to MongoDB

src/config/database.js

import mongoose from "mongoose";

export async function connectDatabase() {
  try {
    await mongoose.connect("mongodb://localhost:27017/blog-api");
    console.log("MongoDB connected");
  } catch (error) {
    console.error("Database connection failed", error);
    process.exit(1);
  }
}

In real projects, this connection string should come from environment variables.


Creating the Blog Post Model

src/models/Post.js

import mongoose from "mongoose";

const postSchema = new mongoose.Schema(
  {
    title: {
      type: String,
      required: true,
      trim: true
    },
    content: {
      type: String,
      required: true
    },
    author: {
      type: String,
      default: "Anonymous"
    }
  },
  {
    timestamps: true
  }
);

export default mongoose.model("Post", postSchema);

Why Mongoose?

Mongoose gives us:

This keeps MongoDB flexible without becoming chaotic.


Creating the Controller

The controller contains the actual logic for handling requests.

src/controllers/postController.js

import Post from "../models/Post.js";

export async function createPost(req, res) {
  try {
    const post = await Post.create(req.body);
    res.status(201).json(post);
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
}

export async function getAllPosts(req, res) {
  const posts = await Post.find().sort({ createdAt: -1 });
  res.json(posts);
}

export async function getPostById(req, res) {
  const post = await Post.findById(req.params.id);

  if (!post) {
    return res.status(404).json({ message: "Post not found" });
  }

  res.json(post);
}

export async function updatePost(req, res) {
  const post = await Post.findByIdAndUpdate(
    req.params.id,
    req.body,
    { new: true }
  );

  if (!post) {
    return res.status(404).json({ message: "Post not found" });
  }

  res.json(post);
}

export async function deletePost(req, res) {
  const post = await Post.findByIdAndDelete(req.params.id);

  if (!post) {
    return res.status(404).json({ message: "Post not found" });
  }

  res.status(204).send();
}

Each function does one thing and does it clearly.


Defining Routes

Routes map HTTP verbs and URLs to controller actions.

src/routes/postRoutes.js

import { Router } from "express";
import {
  createPost,
  getAllPosts,
  getPostById,
  updatePost,
  deletePost
} from "../controllers/postController.js";

const router = Router();

router.post("/", createPost);
router.get("/", getAllPosts);
router.get("/:id", getPostById);
router.put("/:id", updatePost);
router.delete("/:id", deletePost);

export default router;

Setting Up the Express Server

src/server.js

import express from "express";
import { connectDatabase } from "./config/database.js";
import postRoutes from "./routes/postRoutes.js";

const app = express();

// Middleware
app.use(express.json());

// Routes
app.use("/api/posts", postRoutes);

// Start server
const PORT = process.env.PORT || 3000;

connectDatabase().then(() => {
  app.listen(PORT, () => {
    console.log(`Server running on port ${PORT}`);
  });
});

Running the API

Add a dev script to package.json:

{
  "scripts": {
    "dev": "nodemon src/server.js"
  }
}

Run the server:

npm run dev

Testing the API

Create a post

POST /api/posts
{
  "title": "My First Blog Post",
  "content": "This is the content of my first post",
  "author": "James"
}

Get all posts

GET /api/posts

Get a single post

GET /api/posts/{id}

Update a post

PUT /api/posts/{id}
{
  "title": "Updated Title",
  "content": "Updated content"
}

Delete a post

DELETE /api/posts/{id}

Common Mistakes to Avoid

❌ Putting logic in routes

Controllers should handle logic, routes should only map endpoints.


❌ Skipping validation

Always validate request data before saving it.


❌ Not handling missing records

Always return proper 404 responses.


❌ Hardcoding configuration

Use environment variables for database URLs and secrets.


Why This Architecture Scales

This simple Blog API structure:

Adding authentication later doesn’t require a rewrite — just new middleware and routes.


Next Steps

Once this API is working, you can extend it with:

This Express + ES6 + MongoDB foundation is flexible enough to support all of that.


Final Thoughts

Building a simple Blog API with Express, ES6, and MongoDB is one of the best ways to solidify your backend fundamentals. You learn how routing, controllers, models, and databases fit together — without heavy abstractions getting in the way.

If you understand this project, you’re well on your way to building real-world Node.js APIs that scale beyond tutorials.

If you want follow-up posts, I can cover:

Just let me know what you’d like next.

Leave a Reply

Your email address will not be published. Required fields are marked *