Loading

Quipoin Menu

Learn • Practice • Grow

express-js / Mini Full-Stack Project (Blog/E-commerce API)
tutorial

Mini Full-Stack Project (Blog/E-commerce API)

Congratulations! You've learned all the individual pieces of Express.js. Now it's time to put everything together into a **complete full-stack project**. In this chapter, we'll build a Blog/E-commerce API that demonstrates all the concepts you've learned.

Project Options

Choose the project that interests you most:
  • Blog API: Posts, comments, categories, tags, authors.
  • E-commerce API: Products, categories, shopping cart, orders, users.

This project is your capstone – it brings together everything: routing, middleware, database, authentication, file uploads, error handling, and best practices.

Option 1: Blog API Features

  • User registration & login (JWT)
  • Create, read, update, delete posts
  • Add comments to posts
  • Categories and tags for posts
  • Upload featured images for posts
  • Search and filter posts
  • Role-based access (admin, author, reader)

Option 2: E-commerce API Features

  • User registration & login (JWT)
  • Product catalog with categories
  • Product images upload
  • Shopping cart functionality
  • Place orders
  • Order history for users
  • Admin panel for managing products

Project Structure (Both Options)
project-root/
├── models/
│ ├── User.js
│ ├── Post.js (or Product.js)
│ ├── Comment.js (or Order.js)
│ └── Category.js
├── controllers/
│ ├── authController.js
│ ├── postController.js (or productController.js)
│ └── commentController.js (or orderController.js)
├── routes/
│ ├── authRoutes.js
│ ├── postRoutes.js (or productRoutes.js)
│ └── commentRoutes.js (or orderRoutes.js)
├── middleware/
│ ├── auth.js
│ ├── upload.js (multer config)
│ └── errorHandler.js
├── utils/
│ ├── catchAsync.js
│ └── AppError.js
├── config/
│ └── db.js
├── uploads/ (for file uploads)
├── .env
├── app.js
└── server.js

Key Models (Blog API)

Post Model
const postSchema = new mongoose.Schema({
  title: { type: String, required: true, trim: true },
  slug: { type: String, unique: true },
  content: { type: String, required: true },
  excerpt: { type: String, maxlength: 500 },
  featuredImage: { type: String },
  categories: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Category' }],
  tags: [String],
  author: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
  status: { type: String, enum: ['draft', 'published'], default: 'draft' },
  viewCount: { type: Number, default: 0 }
}, { timestamps: true });

Comment Model
const commentSchema = new mongoose.Schema({
  content: { type: String, required: true },
  post: { type: mongoose.Schema.Types.ObjectId, ref: 'Post', required: true },
  user: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
  status: { type: String, enum: ['pending', 'approved'], default: 'pending' }
}, { timestamps: true });

Key Features Implementation

1. Slug Generation for Posts
postSchema.pre('validate', function(next) {
  if (this.title && !this.slug) {
    this.slug = this.title
      .toLowerCase()
      .replace(/[^a-z0-9]+/g, '-')
      .replace(/^-|-$/g, '');
  }
  next();
});

2. Increment View Count
router.get('/:slug', catchAsync(async (req, res) => {
  const post = await Post.findOneAndUpdate(
    { slug: req.params.slug },
    { $inc: { viewCount: 1 } },
    { new: true }
  ).populate('author categories');
 
  res.json({ status: 'success', data: { post } });
});

3. Search and Filter
router.get('/', catchAsync(async (req, res) => {
  const { search, category, tag, sort } = req.query;
 
  let filter = { status: 'published' };
 
  if (search) {
    filter.$or = [
      { title: { $regex: search, $options: 'i' } },
      { content: { $regex: search, $options: 'i' } }
    ];
  }
 
  if (category) filter.categories = category;
  if (tag) filter.tags = tag;
 
  let query = Post.find(filter).populate('author');
 
  if (sort === 'oldest') query = query.sort('createdAt');
  else query = query.sort('-createdAt');
 
  <!-- Pagination -->
  const page = req.query.page * 1 || 1;
  const limit = req.query.limit * 1 || 10;
  const skip = (page - 1) * limit;
 
  query = query.skip(skip).limit(limit);
 
  const posts = await query;
  const total = await Post.countDocuments(filter);
 
  res.json({
    status: 'success',
    results: posts.length,
    total,
    page,
    pages: Math.ceil(total / limit),
    data: { posts }
  });
});

Testing Your API

Use tools to test your API:
  • Postman: Popular API testing tool
  • Insomnia: Alternative to Postman
  • Swagger UI: For API documentation

Deployment Considerations

  • Use environment variables for all configuration
  • Set up MongoDB Atlas for cloud database
  • Use a process manager like PM2
  • Consider using Docker for containerization
  • Deploy to platforms like Heroku, Render, or AWS

Two Minute Drill

  • This capstone project combines everything you've learned about Express.js.
  • Choose between Blog API or E-commerce API based on your interest.
  • Implement proper data relationships between models.
  • Add features like search, pagination, and file uploads.
  • Test thoroughly and deploy to a cloud platform.

Need more clarification?

Drop us an email at career@quipoinfotech.com