Ali-Amir-code / t8-advanced-search

Repository from Github https://github.comAli-Amir-code/t8-advanced-searchRepository from Github https://github.comAli-Amir-code/t8-advanced-search

Blog API with advanced search functionality

A simple RESTful backend for a blog application, built with Express.js, MongoDB and JWT-based authentication. Supports CRUD for posts and authors, pagination, validation, error handling — and a secure comment system with ownership/admin permissions and optional nested replies. It also supports flexible search and multi‑criteria filtering for blog posts.


Table of Contents

  1. Features
  2. Tech Stack
  3. Prerequisites
  4. Project Structure
  5. Setup & Installation
  6. Environment Variables
  7. Database
  8. Running the Server
  9. Authentication
  10. API Endpoints
  11. Validation & Error Handling
  12. Pagination
  13. Notes on Comments & Permissions
  14. Search & Filtering Implementation Notes
  15. Further Improvements

Features

  • User Authentication via JSON Web Tokens (JWT)
  • CRUD operations for blog posts
  • Author registration & lookup (passwords excluded from responses)
  • Pagination support on posts listing
  • Secure Comment System: create/read/update/delete comments tied to posts, owner/admin restrictions, optional nested replies
  • Flexible Search & Multi‑criteria Filtering for posts (search by title/content/tags, date range, category/tags, sorting)
  • Input Validation using express-validator
  • Centralized Error Handling via middleware
  • Protected Routes: only authenticated authors can create/update/delete their own posts and comments (unless admin)

Tech Stack

  • Node.js & Express.js
  • MongoDB with Mongoose ODM
  • JWT for token-based auth
  • bcrypt.js for password hashing
  • dotenv for environment config
  • express-validator for request validation

Prerequisites

  • Node.js v14+
  • MongoDB v4+ (local or Atlas)
  • npm (or yarn)

Project Structure

blog-api/
├── .env
├── package.json
├── index.js
├── config/
│   └── db.js
├── models/
│   ├── Author.js      # includes `role` (author | admin)
│   ├── Post.js        # includes category, tags, indexes
│   └── Comment.js     # comments model (post, author, content, parent, timestamps)
├── routes/
│   ├── auth.js
│   ├── authors.js
│   ├── posts.js
│   ├── comments.js
└── middleware/
    ├── auth.js
    └── errorHandler.js

Setup & Installation

  1. Clone the repo

    git clone https://github.com/ali-amir-code/t8-advanced-search.git
    cd t8-advanced-search
  2. Install dependencies

    npm install
  3. Create .env (see next)

  4. Ensure server.js registers routes (example):

    app.use('/auth', require('./routes/auth'));
    app.use('/authors', require('./routes/authors'));
    app.use('/posts', require('./routes/posts'));
    app.use('/', require('./routes/comments')); // or app.use('/comments', require('./routes/comments'))
    app.use('/', require('./routes/blogs'));    // search/filtering endpoint (optional)

Environment Variables

Create a .env file in the project root with:

PORT=5000
MONGO_URI=mongodb://localhost:27017/blogdb
JWT_SECRET=your_jwt_secret_here
  • PORT — Server port
  • MONGO_URI — MongoDB connection string
  • JWT_SECRET — Secret key for signing JWT tokens

Database

  • Default database: blogdb on localhost.

  • Collections:

    • authors (fields: _id, name, email, password, role) — role is author or admin.
    • posts (fields: _id, title, content, author (ref), category, tags, createdAt)
    • comments(fields: _id, post (ref), author (ref), content, parent (ref|null), createdAt, updatedAt)

Running the Server

  • Development (with auto-reload):

    npm run dev
  • Production:

    npm start

Server will be listening on http://localhost:<PORT>.


Authentication

All protected routes require an Authorization header:

Authorization: Bearer <token>
  • Register: POST /auth/register → returns { token }
    Token payload includes { author: { id, role } } so middleware can check role (admin/author).
  • Login: POST /auth/login → returns { token }

API Endpoints

Auth

Method Endpoint Body Response
POST /auth/register { name, email, password (min 6 chars) } { token }
POST /auth/login { email, password } { token }

Authors

Protected: require Authorization header.

Method Endpoint Response
GET /authors [{ _id, name, email, role }]
GET /authors/:id { _id, name, email, role }

Posts

Public read; protected write/update/delete.

Method Endpoint Query / Body Response
GET /posts ?limit=<n>&page=<p> (optional, defaults: limit=10, page=1) [{ _id, title, content, author:{_id,name}, createdAt }]
GET /posts/:id { _id, title, content, author:{_id,name}, createdAt }
POST /posts { title, content, category?, tags? } (protected) 201 Created + newly created post object
PUT /posts/:id { title? (optional), content? (optional), category?, tags? } Updated post object
DELETE /posts/:id — (protected, owner only) { msg: "Post removed" }

Comments

Protected for create/update/delete. Read is public. Only the comment owner or an admin may update/delete a comment. Supports optional nested replies via a parent field.

Endpoints

  • POST /posts/:id/comments
    Add a comment to a post. Body: { content: string, parent?: commentId | null }
    Validates non-empty content. If parent provided, parent must exist and belong to same post.

  • GET /posts/:id/comments
    Fetch all comments for a post. Returns a flat list or a nested tree (each comment includes children: [] array). Sort order: ascending by createdAt by default.

  • PUT /comments/:id
    Update a comment. Body: { content: string }
    Only owner or admin allowed.

  • DELETE /comments/:id
    Delete a comment. Only owner or admin allowed. (Note: cascade / re-parent behavior configurable.)


Validation & Error Handling

  • Missing fields: returns 400 Bad Request + array of validation errors (e.g., empty comment content is rejected).
  • Unauthorized: returns 401 Unauthorized when token missing/invalid.
  • Forbidden: returns 403 Forbidden when a non-owner/non-admin attempts edit/delete.
  • Not found: returns 404 Not Found for missing posts/authors/comments.
  • Server errors: 500 Internal Server Error with { error }.

All errors funnel through middleware/errorHandler.js for consistent JSON responses.


Pagination

  • Clients may request page-by-page data via query parameters:
GET /posts?limit=5&page=2
  • Response returns up to limit posts, skipping (page-1)*limit.

Comment lists may also be paginated in future (not implemented by default).


Notes on Comments & Permissions

  • Ownership: Comments store author (ObjectId). Only the comment owner (matching req.author.id) or a user with role === 'admin' may update or delete a comment.
  • Nested replies: Implemented with an optional parent field (ObjectId referencing another Comment). GET /posts/:id/comments returns a children tree for nested replies.
  • Delete behavior: By default, deleting a comment removes that single comment. You can choose to implement cascade delete (recursively remove children), re-parent children, or soft-delete (mark as deleted while keeping children).
  • Token payload: Ensure JWT payload includes role, e.g.:
const payload = { author: { id: author.id, role: author.role } };

So middleware/auth.js can expose req.author.id and req.author.role.


Search & Filtering

This project includes a flexible search/filter endpoint to let end-users query posts by keyword, tags, category, date range, sorting and pagination.

Endpoint (example)

GET /blogs?search=keyword&category=tech&tags=nodejs,express&fromDate=2024-01-01&toDate=2024-12-31&sort=latest&page=1&limit=10

Query Parameters

  • search — keyword to search across title, content, and tags. Uses case-insensitive regex by default.
  • category — exact match on post category.
  • tags — comma-separated list (e.g. tags=nodejs,express). Matches posts that contain any of the listed tags by default. Use tags_all=true to require all tags ($all) instead.
  • fromDate — ISO date (YYYY-MM-DD). Inclusive start date for createdAt.
  • toDate — ISO date (YYYY-MM-DD). Inclusive end date for createdAt.
  • sortlatest (default), oldest, alpha_asc, alpha_desc.
  • page — page number (default 1).
  • limit — items per page (default 10, max 100).

Response (paginated)

{
  "total": 42,
  "page": 1,
  "limit": 10,
  "totalPages": 5,
  "results": [
    {
      "_id": "60f5a6f3b1a4c730d8f0e8a3",
      "title": "New Features in Node.js",
      "content": "Node.js v20 introduces …",
      "category": "backend",
      "tags": ["nodejs","performance"],
      "author": { "_id":"60f5a2c4","name":"Alice Smith" },
      "createdAt": "2024-09-12T11:00:00.000Z"
    }
    // ...
  ]
}

Search & Filtering Implementation Notes

  • Search: The implementation uses escaped regex for the search term and applies a case‑insensitive regex to title, content, and tags. This supports partial matches but can be slower than a text index for large datasets.
  • Indexes: Add indexes on createdAt, category, and tags (and consider a text index on title + content for $text queries) to improve performance.
  • Validation: Use express-validator for fromDate, toDate, page, limit, and sort. Return 400 Bad Request with helpful error details for invalid parameters.
  • Date handling: toDate is treated inclusively (set to end of day if no time provided).
  • Combining filters: All filters can be combined in a single request. The route builds a MongoDB filter object and applies $and/$or as needed.
  • Performance tips:
    • Use .lean() to reduce Mongoose overhead.
    • Cap limit to a reasonable maximum (e.g., 100).
    • Consider $text search or a dedicated search engine (Meilisearch, Typesense, Elasticsearch) for advanced/fuzzy search.
    • Cache frequently requested queries (Redis) where appropriate.
  • Advanced options:
    • tags_all=true — require all tags ($all).
    • fields=title,content — projection to return only selected fields.
    • sort=relevance — if switching to $text search.

Further Improvements

  • Soft deletes for comments (preserve thread context).
  • Cascade / re-parent options for replies on delete.
  • Comment pagination for posts with many comments.
  • Likes/upvotes, moderation tools, and reporting.
  • Rate limiting to protect endpoints (e.g., login/comment flood).
  • Swagger/OpenAPI docs for automatic API documentation.
  • Unit & integration tests (Jest, Supertest).
  • Dockerization & CI/CD for production deployment.

About


Languages

Language:JavaScript 100.0%