BookStore REST API (1.0.0)

Download OpenAPI specification:

License: Apache 2.0

REST API for an online bookstore.

This API provides authentication, user management, book management, cart, favourites, orders, and other bookstore-related functionality.

auth

Authentication and account verification endpoints.

Includes:

  • User registration
  • User login
  • Email OTP verification
  • Resending OTP
  • Forgot password
  • Reset password

Register a new user account

Creates a new customer account in the BookStore database using the supplied personal details, contact numbers, date of birth, and physical delivery address.

Upon account creation:

  1. A user record is persisted in MongoDB with role: "user", isEmailVerified: false, isActive: true, and an empty cart and favourites list.
  2. A 6-digit numeric verification OTP is generated with a 30-second expiration window (verificationTokenExpiry).
  3. An HTML verification email is dispatched via Nodemailer to the user's email address (or development mailbox).
  4. If the email fails to deliver, the newly created user record is rolled back and deleted from the database.
  5. The client must submit the received OTP to /auth/verifyOtp within 30 seconds to verify their email and obtain an access token.

Rate limit: 5 requests per minute.

Request Body schema: application/json
required

Personal and delivery details required to register a customer account.

name
required
string >= 2 characters

The user's full name.

email
required
string <email>

Email address used for the user's account.

password
required
string <password> >= 8 characters

Password used to authenticate the user.

dateOfBirth
required
string <date>

The user's date of birth.

phoneNumber
required
integer

The user's 10-digit phone number.

gender
required
string
Enum: "male" "female" "others"

Gender selected by the user.

required
object (Address)

Physical address associated with a user.

Responses

Request samples

Content type
application/json
{
  • "name": "Panchal Keyur",
  • "email": "panchalkeyur.dev@gmail.com",
  • "password": "hello-1234",
  • "dateOfBirth": "2005-06-08",
  • "phoneNumber": 1234567890,
  • "gender": "male",
  • "address": {
    }
}

Response samples

Content type
application/json
{
  • "status": "success",
  • "message": "user is registered, otp is being sent to email for verification",
  • "data": {
    }
}

Authenticate user and receive JWT access token

Authenticates an existing user account using email and password credentials.

Authentication flow:

  1. Express-validator checks that email and password fields are present and well-formed.
  2. User is looked up in MongoDB by email address.
  3. check if user account is deactivated, if it is then return error message
  4. The submitted plain password is verified against the bcrypt password hash.
  5. A JSON Web Token (JWT) signed with JWT_SECRET_KEY and configured expiration (JWT_EXPIRES) is generated containing the user ID payload { id: userId }.
  6. The JWT token and complete user profile are returned to the client.

Client requests to protected endpoints must supply this token in the header: Authorization: Bearer <JWT_TOKEN>

Rate limit: 5 requests per minute.

Request Body schema: application/json
required

User credentials for login authentication.

email
required
string <email>

Email address associated with the user account.

password
required
string <password>

Password associated with the user account.

Responses

Request samples

Content type
application/json
{
  • "email": "hello-1@gmail.com",
  • "password": "hello-1234"
}

Response samples

Content type
application/json
{
  • "status": "success",
  • "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  • "data": {
    }
}

Verify email verification OTP

Verifies the 6-digit one-time password (OTP) sent to the user's email during registration.

Verification logic:

  1. Client provides email and the 6-digit otp.
  2. Server checks if the user account exists in MongoDB.
  3. Verifies whether the account is already verified (isEmailVerified === true).
  4. Checks whether the OTP has expired (Date.now() > verificationTokenExpiry).
  5. Validates the submitted OTP against the stored emailVerifiedToken.
  6. Upon successful verification:
    • isEmailVerified is updated to true.
    • emailVerifiedToken and verificationTokenExpiry are cleared.
    • A signed JWT access token is minted and returned so the user can immediately interact with protected endpoints.

Rate limit: 5 requests per minute.

Request Body schema: application/json
required

Email address and 6-digit verification OTP.

otp
required
integer [ 100000 .. 999999 ]

Six-digit OTP sent to the user's email.

email
required
string <email>

Email address associated with the account.

Responses

Request samples

Content type
application/json
{
  • "email": "panchalkeyur.dev@gmail.com",
  • "otp": 151858
}

Response samples

Content type
application/json
{
  • "status": "success",
  • "message": "otp verified successfully",
  • "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  • "data": {
    }
}

Resend email verification OTP

Generates and sends a new 6-digit verification OTP to the user's registered email address.

Endpoint rules:

  1. The account must exist in the database.
  2. If the user's email is already verified (isEmailVerified === true), resending is rejected with 400.
  3. A fresh OTP is generated with a new 30-second expiry timestamp.
  4. An HTML email with the new OTP is dispatched via Nodemailer.

Rate limit: 5 requests per minute.

Request Body schema: application/json
required

Email address of the unverified customer account.

email
required
string <email>

Email address associated with the user account.

Responses

Request samples

Content type
application/json
{
  • "email": "panchalkeyur.dev@gmail.com"
}

Response samples

Content type
application/json
{
  • "status": "success",
  • "message": "otp is sent to email, please check your email"
}

Request password reset email link

Generates a secure password reset token and emails a reset link to the user.

Security & controller requirements:

  1. Protected Route: Requires a valid JWT Bearer token in the Authorization header (protect middleware).
  2. The authenticated user must have a verified email address (isEmailVerified === true).
  3. The email to reset is provided in the request body.
  4. A 32-byte cryptographically secure random token is generated and SHA-256 hashed into passwordResetToken on the user record.
  5. The reset token has a 30-second expiry (passwordExpires = Date.now() + 30 * 1000).
  6. An email containing the password reset link ${protocol}://${host}/auth/resetPassword/${resetToken} is sent to the customer.

Rate limit: 5 requests per minute.

Authorizations:
bearerAuth
Request Body schema: application/json
required

Email address of the account requesting password reset.

email
required
string <email>

Email address associated with the account.

Responses

Request samples

Content type
application/json
{
  • "email": "panchalkeyur.dev@gmail.com"
}

Response samples

Content type
application/json
{
  • "status": "success",
  • "message": "email send successfully"
}

Reset user password using reset token

Changes the user's password using the unhashed password reset token received via email.

Flow & controller requirements:

  1. Protected Route: Requires a valid JWT Bearer token in the Authorization header (protect middleware).
  2. The reset token is supplied as a URL path parameter :token.
  3. The server hashes :token with SHA-256 and searches for a user where passwordResetToken matches and passwordExpires > Date.now().
  4. If the token is invalid or expired (30-second lifespan), an error is returned.
  5. The new password is set, passwordResetToken and passwordExpires are cleared to undefined, and the user document is saved (which triggers bcrypt hashing via Mongoose pre('save')).

Rate limit: 5 requests per minute.

Authorizations:
bearerAuth
path Parameters
token
required
string
Example: a1b2c3d4e5f67890123456789abcdef0123456789abcdef0123456789abcdef0

Unhashed password reset token string extracted from the email link.

Request Body schema: application/json
required

The new password to replace the current password.

password
required
string <password> >= 8 characters

New password that replaces the existing password.

Responses

Request samples

Content type
application/json
{
  • "password": "hello-1234"
}

Response samples

Content type
application/json
{
  • "status": "success",
  • "message": "password chagned successfully"
}

admin

Administrator endpoints for monitoring and managing the bookstore application.

Get admin dashboard statistics

Retrieves aggregated key performance statistics for the administrator dashboard.

The dashboard aggregates:

  • Total revenue from non-cancelled orders
  • Total count of orders (all statuses)
  • Total books Ordered in system
  • Total sales and order count for the current month
  • Total sales and order count for the current year
  • Daily paid sales for the last 30 days
  • Best-selling book (by units sold and revenue)
  • Total registered users count
  • New users registered during the current month
  • User distribution by non-admin roles (user, seller, etc.)
  • Orders grouped by order status (paid, pending, cancelled, etc.)
  • Pending orders count
  • Books with low inventory (stock <= 10)

Rate limit: 30 requests per minute.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "status": "success",
  • "salesData": {
    },
  • "userStats": {
    },
  • "orderStats": {
    },
  • "lowInventory": [
    ]
}

Get sales and revenue analytics

Retrieves aggregated sales metrics for non-cancelled orders grouped by day, week, or month.

Optional query parameters allow filtering by date range (startDate and endDate) and selecting the aggregation period (groupBy):

  • day: Groups data daily (YYYY-MM-DD) [default]
  • week: Groups data weekly (YYYY-Www)
  • month: Groups data monthly (YYYY-MM)

For each time bucket, the response returns:

  • totalRevenue: Sum of total prices
  • avgRevenue: Average order value
  • totalOrders: Count of orders
  • totalItems: Total quantity of books purchased

Rate limit: 30 requests per minute.

Authorizations:
bearerAuth
query Parameters
startDate
string <date>
Example: startDate=2026-01-01

Earliest order creation date to include (inclusive).

endDate
string <date>
Example: endDate=2026-10-01

Latest order creation date to include (inclusive).

groupBy
string
Default: "day"
Enum: "day" "week" "month"
Example: groupBy=day

Time-series bucket granularity.

Responses

Response samples

Content type
application/json
{
  • "status": "success",
  • "data": [
    ]
}

Get book catalog, sales, and review analytics

Returns three comprehensive analytical datasets across the bookstore:

  1. booksAnalytic: Total books, active books, inactive/deleted books, out-of-stock books, and low-stock books (< 100 units).
  2. bookSaleAnalytics: Top 10 best-selling books and top 10 low-selling books based on quantity sold in paid orders.
  3. bookReviewAnalytics: Top 10 most-rated books and top 10 highest-rated books (by average rating).
Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "stauts": "success",
  • "data": {
    }
}

Get books with zero sales in the last 30 days

Identifies stagnant inventory ("dead stock") books that have generated zero sales in paid orders over the past 30 days.

Returns paginated book items with title, author, current stock, price, and totalSold: 0.

Authorizations:
bearerAuth
query Parameters
page
integer >= 1
Default: 1
Example: page=1

Page number for pagination.

limit
integer >= 1
Default: 2
Example: limit=10

Number of books per page.

Responses

Response samples

Content type
application/json
{
  • "status": "success",
  • "pagination": {
    },
  • "data": [
    ]
}

Get comprehensive performance metrics for all books

Retrieves a paginated list of all books enriched with multi-dimensional performance data:

  • orderAnalytics: Total units sold and total revenue from paid orders.
  • wishlistAnalytics: Total times the book was wishlisted.
  • bookRating: Average customer review rating.
Authorizations:
bearerAuth
query Parameters
page
integer >= 1
Default: 1
Example: page=1

Page number for pagination.

limit
integer >= 1
Default: 10
Example: limit=10

Number of books per page.

Responses

Response samples

Content type
application/json
{
  • "status": "success",
  • "pagination": {
    },
  • "data": [
    ]
}

Get sales quantity and revenue distribution by book category

Calculates total units sold (getSales) and cumulative revenue (getRevenue) across all paid orders, mapped across standard bookstore categories: Fantasy, Action, Adventure, Mystery, Horror, Thriller, Romance, Self-help, and Biography.

Categories without any sales return 0 for both fields.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "status": "success",
  • "data": [
    ]
}

Get month-by-month sales trends per category

Computes monthly sales quantities and revenue per category within a specified date range.

Validations enforced:

  • startDate and endDate are required valid date strings.
  • endDate must be strictly after startDate.
  • The date range between startDate and endDate cannot exceed 1 year.

Missing calendar months in the range are automatically densified with zero values.

Authorizations:
bearerAuth
query Parameters
startDate
required
string <date>
Example: startDate=2026-01-01

Start date in YYYY-MM-DD format.

endDate
required
string <date>
Example: endDate=2026-09-01

End date in YYYY-MM-DD format (must be within 1 year from startDate).

Responses

Response samples

Content type
application/json
{
  • "status": "success",
  • "data": [
    ]
}

Get review rating distribution (1 to 5 stars) per book

Aggregates customer reviews grouped by book, displaying individual counts for 5-star, 4-star, 3-star, 2-star, and 1-star ratings.

Results are paginated.

Authorizations:
bearerAuth
query Parameters
page
integer >= 1
Default: 1
Example: page=1

Page number for pagination.

limit
integer >= 1
Default: 10
Example: limit=10

Number of books per page.

Responses

Response samples

Content type
application/json
{
  • "status": "success",
  • "pagination": {
    },
  • "data": [
    ]
}

Get order status counts and order cancellation analytics

Returns two high-level order metrics:

  1. orderStatusAnalytics: Total count of orders grouped by order status (e.g. paid, pending, cancelled).
  2. orderCancellationAnalytics: Total orders, number of cancelled orders, and calculated cancellation rate percentage.
Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "status": "success",
  • "data": {
    }
}

Get daily order growth over a date range (up to 90 days)

Provides day-by-day order counts between startDate and endDate.

Validations enforced:

  • Both startDate and endDate are required.
  • startDate cannot be later than endDate.
  • The time difference between the dates cannot exceed 90 days.

Days without any order activity are automatically densified with a count of 0.

Authorizations:
bearerAuth
query Parameters
startDate
required
string <date>
Example: startDate=2026-09-01

Start date (YYYY-MM-DD).

endDate
required
string <date>
Example: endDate=2026-09-30

End date (YYYY-MM-DD, within 90 days of startDate).

Responses

Response samples

Content type
application/json
{
  • "status": "success",
  • "data": [
    ]
}

Get monthly average order value (AOV) and revenue trends

Calculates the monthly average order value (avgOrderValue), count of completed paid orders (completedOrders), and total revenue for paid orders within the specified date range.

Validations enforced:

  • startDate and endDate are required.
  • endDate must be strictly after startDate.
  • Date range cannot exceed 1 year.

Months with zero orders return 0 for revenue and average order value.

Authorizations:
bearerAuth
query Parameters
startDate
required
string <date>
Example: startDate=2026-01-01

Start date (YYYY-MM-DD).

endDate
required
string <date>
Example: endDate=2026-10-01

End date (YYYY-MM-DD, within 1 year from startDate).

Responses

Response samples

Content type
application/json
{
  • "status": "success",
  • "data": [
    ]
}

Get customer growth, top-spending customers, and returning customer rate

Provides in-depth customer engagement and retention statistics:

  1. userAnalytics: Monthly count of newly registered users over the date range (densified with 0).
  2. topPayingCustomers: Top 10 customers ranked by total money spent on completed paid orders.
  3. returningCustomers: Total unique buyers, count of repeat customers (> 1 paid order), and returning customer rate percentage.

Validations enforced:

  • startDate and endDate are required.
  • endDate must be greater than or equal to startDate.
  • Date range cannot exceed 1 year.
Authorizations:
bearerAuth
query Parameters
startDate
required
string <date>
Example: startDate=2026-01-01

Start date (YYYY-MM-DD).

endDate
required
string <date>
Example: endDate=2026-10-01

End date (YYYY-MM-DD, within 1 year from startDate).

Responses

Response samples

Content type
application/json
{
  • "status": "success",
  • "data": {
    }
}

Get payment success/failure volumes, amounts, and conversion rates

Analyzes transaction history and financial performance across payment statuses:

  • paymentStatusAnalytics: Volume counts and financial amounts partitioned into successful (paid), failed (failed), and refunded (cancelled) categories.
  • paymentStatusRate: Total payment attempts, success rate percentage, and failure rate percentage rounded to two decimal places.
Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "status": "success",
  • "data": {
    }
}

Activate / unsuspend a user account

Restores and activates a suspended user account by setting isActive: true and persisting the change with user.save(). Once activated, the customer regains access to their account, can log in, and place bookstore orders.

Authentication & Access Control

  • Required Authentication: Bearer JWT token in the Authorization header (protect middleware).
  • Role Restriction: Strictly restricted to administrators (restrictTo("admin")).

Validation & Rate Limiting

  • ID Validation: validateId("userId") validates that userId is a valid 24-character hexadecimal MongoDB ObjectId. Returns HTTP 400 Bad Request ("Invalid Id, please enter correct id") if malformed.
  • Rate Limiting: Protected by mutationLimiter (maximum 10 mutation requests per minute) and router-level getRateLimiter (maximum 30 requests per minute).
Authorizations:
bearerAuth
path Parameters
userId
required
string^[0-9a-fA-F]{24}$
Example: 683aa9c34ae6c56e60594eb2

24-character hexadecimal MongoDB ObjectId of the user account to activate.

Responses

Response samples

Content type
application/json
{
  • "status": "success",
  • "message": "User is activated",
  • "data": {
    }
}

Suspend / deactivate a user account

Suspends and deactivates a user account by setting isActive: false using User.findByIdAndUpdate. Once deactivated, the user is blocked from logging in or performing customer operations, and excluded from public user queries.

Authentication & Access Control

  • Required Authentication: Bearer JWT token in the Authorization header (protect middleware).
  • Role Restriction: Strictly restricted to administrators (restrictTo("admin")).

Security & Business Constraints

  • Self-Deactivation Guard: An administrator cannot suspend their own account (userId === req.user.id). Attempting to do so returns HTTP 400 Bad Request ("You can't deactivate your self").
  • Admin Account Protection: Administrators cannot suspend other administrator accounts (user.role === 'admin'). Attempting to do so returns HTTP 400 Bad Request ("You can't deactivate admin user").

Validation & Rate Limiting

  • ID Validation: validateId("userId") validates that userId is a valid 24-character hexadecimal MongoDB ObjectId. Returns HTTP 400 Bad Request ("Invalid Id, please enter correct id") if malformed.
  • Rate Limiting: Protected by mutationLimiter (maximum 10 mutation requests per minute) and router-level getRateLimiter (maximum 30 requests per minute).
Authorizations:
bearerAuth
path Parameters
userId
required
string^[0-9a-fA-F]{24}$
Example: 683aa9c34ae6c56e60594eb2

24-character hexadecimal MongoDB ObjectId of the user account to deactivate.

Responses

Response samples

Content type
application/json
{
  • "status": "success",
  • "message": "User is suspended",
  • "data": {
    }
}

Modify a user's role

Changes the authorization role of a user account. Permits switching between "user" and "admin".

Authentication & Access Control

  • Required Authentication: Bearer JWT token in the Authorization header (protect middleware).
  • Role Restriction: Strictly restricted to administrators (restrictTo("admin")).

Security & Role Constraints

  • Self-Role Modification Guard: An administrator cannot alter their own role (userId === req.user.id). Attempting to do so returns HTTP 400 Bad Request ("You can't change your role").
  • Valid Role Enforcements: Only roles included in ["admin", "user"] are accepted. Any other string value triggers HTTP 400 Bad Request ("Please provide valid role").

Validation & Rate Limiting

  • ID Validation: validateId("userId") validates that userId is a valid 24-character hexadecimal MongoDB ObjectId. Returns HTTP 400 Bad Request ("Invalid Id, please enter correct id") if malformed.
  • Rate Limiting: Protected by mutationLimiter (maximum 10 mutation requests per minute) and router-level getRateLimiter (maximum 30 requests per minute).
Authorizations:
bearerAuth
path Parameters
userId
required
string^[0-9a-fA-F]{24}$
Example: 683aa9c34ae6c56e60594eb2

24-character hexadecimal MongoDB ObjectId of the target user whose role is to be updated.

Request Body schema: application/json
required

JSON payload containing the new role assignment.

role
required
string
Enum: "admin" "user"

Role to assign to the user ("admin" or "user").

Responses

Request samples

Content type
application/json
{
  • "role": "admin"
}

Response samples

Content type
application/json
{
  • "status": "success",
  • "message": "User role changed successfully",
  • "data": {
    }
}

books

Book catalog, inventory, and product management endpoints.

Includes:

  • Public catalog browsing with title and author regex search
  • Sorting (newest, oldest) and pagination controls
  • Single book lookup with high-speed Redis caching
  • Administrator book creation with Cloudinary cover image upload
  • Administrator book updates with metadata editing and cover image replacement
  • Administrator soft-deletion preserving historical order data

Retrieve all books with search, sort, and pagination

Retrieves a paginated collection of active books from the catalog.

Supports keyword filtering by book title and author using case-insensitive regular expressions ($regex, $options: "i"). Results can be sorted in descending (newest) or ascending (oldest) chronological order by creation date.

Soft Deletion & Visibility

Soft-deleted books (isDeleted: true) are automatically excluded from the result set by a Mongoose pre(/^find/) query middleware.

Search & Filtering Capabilities

  • Title Search: Substring match against book titles.
  • Author Search: Substring match against author names.
  • Both filters can be used independently or combined.

Sorting Behavior

  • sort=new (default): Sorts descending by -createdAt (newest books first).
  • sort=old: Sorts ascending by createdAt (oldest books first).
  • Any unrecognized sort parameter defaults to new.

Pagination Rules

  • page: 1-based page index (defaults to 1).
  • limit: Number of records returned per page (defaults to 10).
  • Upper Bound: If limit exceeds 100, the server automatically caps it at 100.
  • Computes skip = (page - 1) * limit.
  • Computes totalPages = Math.ceil(totalItems / limit) and hasNextPage = page < totalPages.

Rate Limiting

  • Protected by getRateLimiter: Maximum 30 requests per minute per client IP.
query Parameters
title
string
Example: title=clean

Case-insensitive substring search for book title. Matches any book whose title contains the specified query text.

author
string
Example: author=martin

Case-insensitive substring search for author name. Matches any book written by an author matching the query string.

sort
string
Default: "new"
Enum: "new" "old"
Example: sort=new

Ordering criterion for the returned books:

  • new: Newest books first (sorted descending by creation date -createdAt).
  • old: Oldest books first (sorted ascending by creation date createdAt). Defaults to new if omitted or if an invalid option is provided.
page
integer >= 1
Default: 1
Example: page=1

1-based page number for paginated results.

limit
integer [ 1 .. 100 ]
Default: 10
Example: limit=10

Number of book records returned per page. Maximum allowed value is 100. Values exceeding 100 are automatically clamped to 100 by the server.

Responses

Response samples

Content type
application/json
Example
{
  • "status": "success",
  • "length": 2,
  • "pagination": {
    },
  • "message": "all books found",
  • "data": [
    ]
}

Create a new book with cover image upload

Creates and registers a new book entity in the bookstore catalog.

This operation is restricted to verified administrators (role: 'admin'). The request must be transmitted as multipart/form-data to accommodate both book metadata fields and the binary image file for the book's cover.

Creation & Upload Flow

  1. Authentication: Caller provides a valid JWT Bearer token in the Authorization header.
  2. Authorization: restrictTo("admin") middleware verifies the caller holds admin role and that their email is verified.
  3. Rate Limiting: mutationLimiter restricts the caller to 10 mutations per minute.
  4. File Handling: Multer parses the multipart request, extracting the file from field coverImage and writing it to temporary disk storage (uploads/).
  5. Validation: validateBooks validates the presence and constraints of title, author, stock, description, price, and category.
  6. Cloudinary Upload: The server uploads the temporary cover image to Cloudinary under the "BookStore" folder.
  7. Cleanup: The local temporary file is deleted from disk using fs.unlink.
  8. Database Persistence: A new document is saved in MongoDB with the resulting Cloudinary HTTPS URL and initial defaults (totalSales: 0, ratingAverage: 0, ratingQuantity: 0, isDeleted: false).
  9. Response: Returns HTTP 201 Created with the complete book document.

Validation Rules

  • title: String, trimmed, non-empty, minimum length of 2 characters.
  • author: String, non-empty.
  • stock: Numeric, non-empty, non-negative integer.
  • description: String, non-empty.
  • price: Numeric, non-empty, non-negative, minimum length 1 character.
  • category: Must match one of the predefined categories: Fantasy, Action, Adventure, Mystery, Horror, Thriller, Romance, Self-help, Biography. Cannot be empty.
  • coverImage: Required binary file representing the book cover art.
Authorizations:
bearerAuth
Request Body schema: multipart/form-data
required

Multipart form data containing book metadata and the cover image file.

title
required
string >= 2 characters

Title or name of the book (minimum 2 characters).

author
required
string

Full name of the author. Cannot be empty.

stock
required
integer >= 0

Initial inventory quantity. Must be a valid non-negative number.

description
required
string

Detailed description or synopsis of the book content.

price
required
number <double> >= 0

Retail price of the book. Must be non-negative and at least 1 character in length.

category
required
string
Enum: "Fantasy" "Action" "Adventure" "Mystery" "Horror" "Thriller" "Romance" "Self-help" "Biography"

Genre category selected from the predefined list of allowed categories.

coverImage
required
string <binary>

Cover image file (JPEG, PNG, WebP) uploaded via form-data. The server automatically transmits this file to Cloudinary in the BookStore folder and deletes the local temporary file after upload.

Responses

Response samples

Content type
application/json
{
  • "status": "success",
  • "message": "Book is created",
  • "data": {
    }
}

Retrieve a book by its unique ID (with Redis caching)

Retrieves detailed information for a specific book identified by its unique MongoDB ObjectId.

High-Performance Redis Caching

This endpoint implements a cache-aside caching strategy using Redis:

  1. The server checks for the Redis key book:{bookId}.
  2. Cache Hit: If the key exists, cached JSON data is parsed and returned immediately without accessing the MongoDB database.
  3. Cache Miss:
    • Validates that bookId parameter is present and valid.
    • Queries MongoDB via Books.findById(bookId).
    • The Mongoose pre(/^find/) middleware automatically filters out soft-deleted books (isDeleted: false).
    • If the book is not found in MongoDB, returns HTTP 404 Not Found.
    • If found, writes the serialized book document into Redis under book:{bookId} and returns HTTP 200 OK.

Rate Limiting

  • Protected by getRateLimiter: Maximum 30 requests per minute per client IP.
path Parameters
bookId
required
string
Example: 683aab454ae6c56e60594eb7

24-character hexadecimal MongoDB ObjectId of the book to retrieve.

Responses

Response samples

Content type
application/json
{
  • "status": "success",
  • "message": "Book is found",
  • "data": {
    }
}

Update book details or replace cover image

Updates an existing book's metadata fields or replaces its cover image.

This operation is restricted to verified administrators (role: 'admin').

Update Workflow

  1. ID Validation: validateId("bookId") middleware verifies that bookId is a syntactically valid 24-character hexadecimal MongoDB ObjectId.
  2. Authentication & Authorization: protect and restrictTo("admin") ensure caller has active admin credentials.
  3. Rate Limiting: mutationLimiter enforces a rate limit of 10 requests per minute.
  4. Image Replacement (Optional): If a new coverImage file is attached via multipart/form-data:
    • The file is temporarily stored by Multer.
    • Uploaded to Cloudinary under the "BookStore" folder.
    • The local temporary file is removed via fs.unlink.
    • The new Cloudinary secure_url replaces the existing coverImage in the update payload.
  5. Database Update: Calls Books.findByIdAndUpdate(bookId, updatePayload).
  6. Cache Refresh: The updated book object is serialized and written to Redis key book:{bookId}, ensuring subsequent GET requests immediately reflect changes.
  7. Response: Returns HTTP 200 OK with the updated book entity.

Request Formats Supported

  • multipart/form-data: Use when replacing the cover image (with or without textual metadata changes).
  • application/json: Use when updating only text or numeric fields (title, author, price, stock, description, category).
Authorizations:
bearerAuth
path Parameters
bookId
required
string
Example: 683aab454ae6c56e60594eb7

24-character hexadecimal MongoDB ObjectId of the book to update.

Request Body schema:
optional

Fields to be updated. All fields are optional; only provided fields are changed.

title
string >= 2 characters

Updated book title (minimum 2 characters).

author
string

Updated author name.

stock
integer >= 0

Updated inventory stock quantity.

description
string

Updated synopsis or description.

price
number <double> >= 0

Updated retail price.

category
string
Enum: "Fantasy" "Action" "Adventure" "Mystery" "Horror" "Thriller" "Romance" "Self-help" "Biography"

Updated genre category.

coverImage
string <binary>

Optional replacement cover image file. If supplied, the image is uploaded to Cloudinary, and the book's coverImage attribute is updated to the newly generated URL.

Responses

Request samples

Content type
No sample

Response samples

Content type
application/json
{
  • "status": "success",
  • "message": "book is updated",
  • "data": {
    }
}

Soft-delete a book from the catalog

Performs a soft deletion on the book specified by bookId.

This operation is restricted to verified administrators (role: 'admin').

Soft-Deletion Architecture

Rather than permanently purging the record from MongoDB, the controller updates the document with { isDeleted: true }:

  1. Preserves sales history, order relations, and aggregate analytics integrity.
  2. Mongoose pre(/^find/) middleware automatically intercepts all queries (find, findOne, findById) and applies { isDeleted: false }, ensuring deleted books are immediately hidden from the public store catalog.
  3. If the book does not exist or was already deleted, returns HTTP 404 Not Found.

Rate Limiting

  • Protected by generalRateLimiter: Maximum 15 requests per minute per client IP.
Authorizations:
bearerAuth
path Parameters
bookId
required
string
Example: 683aab454ae6c56e60594eb7

24-character hexadecimal MongoDB ObjectId of the book to soft-delete.

Responses

Response samples

Content type
application/json
{
  • "status": "success",
  • "message": "Book is deleted"
}

cart

Shopping cart operations for authenticated customers.

Includes:

  • Retrieving active user shopping cart with Redis caching
  • Adding books to cart with real-time inventory validation and dynamic pricing recalculation
  • Removing items from cart with automatic price and quantity reconciliation

Retrieve the authenticated user's shopping cart

Retrieves the active shopping cart for the authenticated customer.

This endpoint requires authentication and is restricted to customers with role: 'user'. The user's email address must be verified.

High-Performance Redis Caching Architecture

The cart utilizes a cache-aside caching strategy via Redis:

  1. Cache Lookup: Checks Redis key user:{userId}:cart.
  2. Cache Hit:
    • If cached data is present, the server parses the JSON string and responds immediately with HTTP 200 OK without touching the MongoDB database: { status: "success", message: "cart is found", data: cartData }.
  3. Cache Miss:
    • Queries MongoDB for an existing cart via Cart.findOne({ user: userId }).
    • Writes the serialized result into Redis under key user:{userId}:cart.
    • If a cart exists in the database, returns HTTP 200 OK with { status: "success", data: getCart }.
    • If the user has not created or added any items to their cart yet, data is null.

Rate Limiting

  • Protected by getRateLimiter: Maximum 30 requests per minute per client IP.
Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
Example
{
  • "status": "success",
  • "message": "cart is found",
  • "data": {
    }
}

Add a book to the shopping cart or increment quantity

Adds a specified quantity of a book to the authenticated customer's shopping cart.

If a cart does not yet exist for the user, a new one is initialized. If the item is already in the cart, its quantity is increased and financial totals are recalculated. Synchronizes changes with Redis caching.

This endpoint requires authentication and is restricted to customers with role: 'user'.

In-Depth Business & Controller Logic

  1. Input Extraction:
    • Extracts bookId and quantity from request body.
    • Extracts userId from authenticated req.user.id.
  2. Inventory Stock Pre-Check:
    • Queries Books.findById(bookId).
    • Verifies that book.stock >= quantity. If the requested quantity exceeds total book stock, rejects immediately with HTTP 400 Bad Request: "No book stock is available yet, please contact admin to futher information".
  3. Cart Discovery & Evaluation:
    • Queries MongoDB for an existing cart via Cart.findOne({ user: userId }).
  4. Branch A: Cart Does Not Exist:
    • Initializes a new Cart document:
      {
        "user": "userId",
        "items": [{ "book": "bookId", "quantity": quantity }],
        "totalQuantity": quantity,
        "totalPrice": book.price * quantity
      }
      
  5. Branch B: Cart Already Exists:
    • Searches for bookId within cart.items:
      • Case 1: Book already exists in cart (index > -1):
        • Calculates newTotalQty = existingQty + quantity.
        • Stock Validation: If newTotalQty > book.stock, rejects with HTTP 400 Bad Request: "Only <availableStock> more units available".
        • Increments item quantity: cart.items[index].quantity += quantity.
        • Increments totals: cart.totalQuantity += quantity, cart.totalPrice += book.price * quantity.
      • Case 2: Book is new to this existing cart (index === -1):
        • Stock Validation: If quantity > book.stock, rejects with HTTP 400 Bad Request: "Only <availableStock> more units available".
        • Pushes new item to cart.items: { book: bookId, quantity }.
        • Increments totals: cart.totalQuantity += quantity, cart.totalPrice += book.price * quantity.
  6. Persistence & Cache Sync:
    • Persists cart to MongoDB: await cart.save().
    • Updates Redis cache key user:{userId}:cart with the newly saved cart JSON.
  7. Response:
    • Returns HTTP 200 OK with { status: "success", message: "added to cart", data: cart }.

Rate Limiting

  • Protected by mutationLimiter: Maximum 10 mutations per minute per client IP.
Authorizations:
bearerAuth
Request Body schema: application/json
required

Book identifier and quantity to add to the cart.

bookId
required
string

24-character hexadecimal MongoDB ObjectId of the book to add.

quantity
required
integer >= 1

Number of copies to add to the cart. Must be at least 1 and within available inventory stock.

Responses

Request samples

Content type
application/json
{
  • "bookId": "683aab454ae6c56e60594eb7",
  • "quantity": 2
}

Response samples

Content type
application/json
{
  • "status": "success",
  • "message": "added to cart",
  • "data": {
    }
}

Remove a book from the shopping cart

Removes a specific book item entirely from the authenticated customer's shopping cart.

Automatically recalculates cumulative price (totalPrice) and quantity (totalQuantity) based on the removed book's unit price, and synchronizes the updated cart with Redis cache.

This endpoint requires authentication and is restricted to customers with role: 'user'.

In-Depth Business & Controller Logic

  1. Parameter & ObjectId Validation:
    • Middleware validateId("bookId") validates that bookId is a syntactically valid 24-character hexadecimal MongoDB ObjectId (mongoose.Types.ObjectId.isValid). If invalid, returns HTTP 400 Bad Request: "Invalid Id, please enter correct id".
    • If bookId is missing, returns HTTP 400 Bad Request: "please provide book id to remove a book from the cart".
  2. Cart Discovery:
    • Looks up the user's cart in MongoDB: Cart.findOne({ user: id }).
    • If no cart exists for the user, returns HTTP 404 Not Found: "cart not found, please create your cart first".
  3. Item Identification:
    • Searches for the book within cart.items: index = findExistingCart.items.findIndex(item => item.book.toString() === bookId).
    • If the book is not present in the cart (index === -1), returns HTTP 404 Not Found: "book not found in the cart".
  4. Price & Quantity Reconciliation:
    • Extracts the removed item's stored quantity: removedQty = removedItem.quantity.
    • Queries the book details from MongoDB (Books.findById(removedItem.book._id)) to get its unit price.
    • Computes deducted price: removedPrice = findBook.price * removedQty.
    • Splices the item out of the items array: cart.items.splice(index, 1).
    • Subtracts from totals:
      • cart.totalPrice -= removedPrice
      • cart.totalQuantity -= removedQty
    • Empty Cart Handling: If all items have been removed (cart.items.length === 0), explicitly resets totalPrice = 0 and totalQuantity = 0.
  5. Persistence & Cache Sync:
    • Saves the updated cart in MongoDB: await findExistingCart.save().
    • Updates Redis key user:{userId}:cart with the serialized updated cart.
  6. Response:
    • Returns HTTP 200 OK with { status: "success", message: "book was removed", data: findExistingCart }.

Rate Limiting

  • Protected by mutationLimiter: Maximum 10 mutations per minute per client IP.
Authorizations:
bearerAuth
path Parameters
bookId
required
string
Example: 683aab454ae6c56e60594eb7

24-character hexadecimal MongoDB ObjectId of the book to remove from the cart.

Responses

Response samples

Content type
application/json
{
  • "status": "success",
  • "message": "book was removed",
  • "data": {
    }
}

orders

Order processing, Stripe checkout, refund requests, and fulfillment tracking.

Includes:

  • Creating Stripe checkout sessions with inventory reservations and cart conversion
  • Processing customer payment refunds with eligibility verification (7-day window)
  • Administrator platform-wide order monitoring, sorting, and pagination
  • Single order lookup with high-speed Redis caching
  • Stripe payment completion and redirection handling

Create a Stripe checkout session for the authenticated user's cart

Initializes a secure, Stripe-hosted payment checkout session for all books currently stored in the authenticated customer's shopping cart.

Authentication & Access Control

  • Required Authentication: Bearer JWT token in the Authorization header (protect middleware).
  • Role Restriction: Strictly restricted to customers with role: 'user' (restrictTo("user")).
  • Email Verification: User account email address must be verified (isEmailVerified: true).

Complete Checkout & Inventory Lifecycle

  1. User & Cart Lookup: Retrieves the customer document and active cart via Cart.findOne({ user: req.user.id }) with populated book details (populate("items.book")). If no cart exists, returns HTTP 404 Not Found.
  2. Inventory Stock Validation & Reservation (makeReservation middleware):
    • Inspects every item in the cart against active inventory in the Books collection (Books.findById(item.book)).
    • If any requested quantity exceeds currently available inventory (book.stock < item.quantity), checkout halts immediately with HTTP 400 Bad Request ("We have only [stock] of [title] left").
    • Deletes any prior unfulfilled reservation for this user (Reservation.findByIdAndDelete).
    • Creates a new temporary reservation record in MongoDB (Reservation.create) to hold inventory while payment is processed.
  3. Stripe Checkout Session Creation:
    • Converts line items into Stripe line item format with currency: "inr", book title, unit amount (price converted to paise: unit_amount = book.price * 100), and quantity.
    • Calls stripe.checkout.sessions.create configured with mode: "payment" and payment_method_types: ["card"].
    • Dynamic redirect callback URLs:
      • success_url: {host}/orders/success?session_id={CHECKOUT_SESSION_ID}
      • cancel_url: {host}/orders/cancel
  4. Asynchronous Order Fulfillment via Queue (orderQueue):
    • Upon successful payment authorization, Stripe dispatches a checkout.session.completed webhook event.
    • The webhook handler enqueues an order-processing background job into BullMQ orderQueue.
    • A dedicated worker processes the session: generates the final Order record, marks the cart isOrdered: true, decrements book stock, updates sales metrics, and cleans up the reservation.

Rate Limiting

  • Protected by mutationLimiter: Maximum 10 mutation requests per minute per client IP.
Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{}

Create a Stripe checkout session for the authenticated user's cart

Initializes a secure, Stripe-hosted payment checkout session for all books currently stored in the authenticated customer's shopping cart.

Authentication & Access Control

  • Required Authentication: Bearer JWT token in the Authorization header (protect middleware).
  • Role Restriction: Strictly restricted to customers with role: 'user' (restrictTo("user")).
  • Email Verification: User account email address must be verified (isEmailVerified: true).

Complete Checkout & Inventory Lifecycle

  1. User & Cart Lookup: Retrieves the customer document and active cart via Cart.findOne({ user: req.user.id }) with populated book details (populate("items.book")). If no cart exists, returns HTTP 404 Not Found.
  2. Inventory Stock Validation & Reservation (makeReservation middleware):
    • Inspects every item in the cart against active inventory in the Books collection (Books.findById(item.book)).
    • If any requested quantity exceeds currently available inventory (book.stock < item.quantity), checkout halts immediately with HTTP 400 Bad Request ("We have only [stock] of [title] left").
    • Deletes any prior unfulfilled reservation for this user (Reservation.findByIdAndDelete).
    • Creates a new temporary reservation record in MongoDB (Reservation.create) to hold inventory while payment is processed.
  3. Stripe Checkout Session Creation:
    • Converts line items into Stripe line item format with currency: "inr", book title, unit amount (price converted to paise: unit_amount = book.price * 100), and quantity.
    • Calls stripe.checkout.sessions.create configured with mode: "payment" and payment_method_types: ["card"].
    • Dynamic redirect callback URLs:
      • success_url: {host}/orders/success?session_id={CHECKOUT_SESSION_ID}
      • cancel_url: {host}/orders/cancel
  4. Asynchronous Order Fulfillment via Queue (orderQueue):
    • Upon successful payment authorization, Stripe dispatches a checkout.session.completed webhook event.
    • The webhook handler enqueues an order-processing background job into BullMQ orderQueue.
    • A dedicated worker processes the session: generates the final Order record, marks the cart isOrdered: true, decrements book stock, updates sales metrics, and cleans up the reservation.

Rate Limiting

  • Protected by mutationLimiter: Maximum 10 mutation requests per minute per client IP.
Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{}

Request a Stripe payment refund for an eligible paid order

Initiates a customer payment refund through the Stripe payment gateway for a completed order.

Authentication & Access Control

  • Required Authentication: Bearer JWT token (protect middleware).
  • Role Restriction: Strictly restricted to customers with role: 'user' (restrictTo("user")).
  • Email Verification: User account email address must be verified (isEmailVerified: true).

Eligibility Criteria & Validation Rules (checkRefundStatus middleware)

  1. Order Ownership Verification: Queries MongoDB for an order where paymentInfo.stripePaymentId matches the path parameter and user matches the authenticated customer (req.user._id). If no matching order is found, returns HTTP 404 Not Found ("Order not found").
  2. 7-Day Cancellation Window Enforcement: Refunds are strictly permitted within 168 hours (7 calendar days) of order payment (paidAt). If todayDate > (paidAt + 168 hours), the request is rejected with HTTP 400 Bad Request ("date is passed, you can't make a refund request").
  3. Order Status Requirement: The order must be in "paid" status. Unpaid, pending, or already cancelled orders cannot be refunded ("This payment cannot be refunded").

Refund Execution & Catalog Reconciliation

  • Invokes stripe.refunds.create({ payment_intent: stripePaymentId, reason: "requested_by_customer" }).
  • Automated Webhook Synchronization (charge.refunded): Upon Stripe refund confirmation, the incoming webhook handler:
    • Updates order status: orderStatus = "cancelled", paymentInfo.status = "cancelled".
    • Executes Mongoose bulkWrite to replenish catalog stock (stock += quantity) and decrement revenue figures (totalSales -= salesAmount) on affected Books documents.

Rate Limiting

  • Protected by rate limiting: Maximum 30 requests per minute per client IP.
Authorizations:
bearerAuth
path Parameters
stripePaymentId
required
string
Example: pi_3NzABC1234567890XYZ

The Stripe Payment Intent identifier associated with the order (e.g., pi_3Nz...).

Responses

Response samples

Content type
application/json
{
  • "status": "success",
  • "message": "payment refund successfull",
  • "data": {
    }
}

Retrieve all platform orders with sorting and pagination (Admin only)

Retrieves a paginated list of all customer orders across the platform for administrative auditing, status tracking, and fulfillment operations.

Authentication & Access Control

  • Required Authentication: Bearer JWT token (protect middleware).
  • Role Restriction: Strictly restricted to users holding role: 'admin' (restrictTo("admin")).
  • Email Verification: Admin account email address must be verified (isEmailVerified: true).

Sorting Behavior

  • sort=new (default): Sorts descending by -createdAt (most recent orders first).
  • sort=old: Sorts ascending by createdAt (oldest orders first).
  • Unrecognized or omitted sort parameter automatically defaults to new.

Pagination Rules

  • page: 1-based page index (defaults to 1).
  • limit: Number of records returned per page (defaults to 10).
  • Upper Bound: If limit exceeds 100, the server automatically caps it at 100.
  • Computes skip = (page - 1) * limit.
  • Computes totalPages = Math.ceil(totalItems / limit) and hasNextPage = page < totalPages.
  • Dynamic response message: "all orders found successfully" when records match, or "orders not found" when the catalog yields 0 records.

Rate Limiting

  • Protected by getRateLimiter: Maximum 30 requests per minute per client IP.
Authorizations:
bearerAuth
query Parameters
page
integer >= 1
Default: 1
Example: page=1

1-based page index for pagination. Defaults to 1.

limit
integer [ 1 .. 100 ]
Default: 10
Example: limit=10

Number of order records to return per page. Defaults to 10. Automatically clamped to a maximum of 100 by the server.

sort
string
Default: "new"
Enum: "new" "old"
Example: sort=new

Chronological ordering of orders:

  • new: Newest orders first (descending by -createdAt).
  • old: Oldest orders first (ascending by createdAt). Defaults to new if omitted or invalid.

Responses

Response samples

Content type
application/json
{
  • "status": "success",
  • "length": 2,
  • "message": "all orders found successfully",
  • "pagination": {
    },
  • "data": [
    ]
}

Retrieve an order by unique ID (with Redis caching)

Retrieves the complete document details of an individual order by its unique identifier, utilizing a high-performance Redis cache-aside caching pattern.

Authentication & Access Control

  • Required Authentication: Bearer JWT token (protect middleware).
  • Role Restriction: Accessible to customers and administrators (role: 'user' or 'admin').
  • Email Verification: User account email address must be verified (isEmailVerified: true).
  • Parameter Validation: Middleware validateId("orderId") verifies that orderId is a syntactically valid 24-character hexadecimal MongoDB ObjectId before controller execution.

High-Performance Redis Cache-Aside Architecture

  1. Cache Lookup: Queries Redis in-memory cache for key order:{orderId} using client.get(...).
  2. Cache Hit:
    • Returns cached serialized order JSON immediately from memory without querying MongoDB.
    • Responds with HTTP 200 OK: { status: "success", data: JSON.parse(orderData) }.
    • Queries MongoDB via Order.findById(orderId).
    • If no order exists, aborts with HTTP 404 Not Found ("Order not found").
    • Ownership Verification: Enforces that the order belongs to the authenticated customer (order.user.toString() === req.user.id.toString()). If the order belongs to another customer, access is denied with HTTP 404 Not Found ("Order not found").
    • If valid and verified:
      • Serializes the order document and stores it in Redis under key order:{orderId}.
      • Responds with HTTP 200 OK: { status: "success", data: order }.

Rate Limiting

  • Protected by getRateLimiter: Maximum 30 requests per minute per client IP.
Authorizations:
bearerAuth
path Parameters
orderId
required
string^[0-9a-fA-F]{24}$
Example: 683b1c204ae6c56e60594ed0

The 24-character hexadecimal MongoDB ObjectId uniquely identifying the order.

Responses

Response samples

Content type
application/json
{
  • "status": "success",
  • "data": {
    }
}

Stripe Checkout payment completion redirect handler

Handles client redirection callback from Stripe hosted checkout following payment completion.

Workflow

  1. Receives the session_id query parameter forwarded by Stripe upon checkout completion.
  2. Validates session state with Stripe via stripe.checkout.sessions.retrieve(req.query.session_id).
  3. Issues an HTTP redirect (res.redirect("/")) forwarding the customer to the storefront homepage.
query Parameters
session_id
required
string
Example: session_id=cs_test_a1b2c3d4e5f67890

The Stripe Checkout Session ID passed by Stripe upon customer payment completion.

Responses

Response samples

Content type
text/html
<p>Payment successful. Redirecting...</p>

reviews

Customer book review and rating management endpoints.

Includes:

  • Retrieving paginated customer reviews and star ratings for a specific book
  • Submitting customer reviews with automatic book aggregate rating recalculation
  • Updating user reviews and modifying star ratings
  • Deleting customer reviews with automated catalog score reconciliation
  • Administrator catalog-wide review monitoring, searching, and pagination
  • High-performance personal review retrieval with Redis cache-aside caching

Retrieve all customer reviews for a specific book

Retrieves a paginated list of customer reviews and ratings for the specified book.

Authentication & Authorization

  • Required Authentication: Bearer JWT token in the Authorization header (protect middleware).
  • Email Verification: User account email address must be verified (isEmailVerified: true).
  • Keyword Search (msg): Optional case-insensitive regular expression substring filter ({ review: { $regex: msg, $options: "i" } }). Matches any review whose commentary contains the query text.
  • Book Scoping: Strictly scoped to the specified bookId ({ book: new mongoose.Types.ObjectId(bookId) }).

Sorting Behavior

  • sort=new (default): Sorts descending by -createdAt (newest reviews first).
  • sort=old: Sorts ascending by createdAt (oldest reviews first).
  • Any unrecognized or omitted sort option automatically defaults to new.

Pagination Rules

  • page: 1-based page index (defaults to 1).
  • limit: Number of records returned per page (defaults to 10).
  • Upper Bound: If limit exceeds 100, the server automatically caps it at 100.
  • Computes skip = (page - 1) * limit.
  • Computes totalPages = Math.ceil(totalItems / limit) and hasNextPage = page < totalPages.

Data Population

  • Automatically populates the author's public name (user: { _id, name }) and book title (book: { _id, title }) via Mongoose pre(/^find/) query middleware.

Rate Limiting

  • Protected by getRateLimiter: Maximum 30 requests per minute per client IP.
Authorizations:
bearerAuth
path Parameters
bookId
required
string^[0-9a-fA-F]{24}$
Example: 683aab454ae6c56e60594eb7

The 24-character hexadecimal MongoDB ObjectId uniquely identifying the book.

query Parameters
page
integer >= 1
Default: 1
Example: page=1

1-based page index for pagination. Defaults to 1.

limit
integer [ 1 .. 100 ]
Default: 10
Example: limit=10

Number of review records to return per page. Defaults to 10. Automatically clamped to a maximum of 100 by the server.

sort
string
Default: "new"
Enum: "new" "old"
Example: sort=new

Chronological ordering of reviews:

  • new: Newest reviews first (descending by -createdAt).
  • old: Oldest reviews first (ascending by createdAt). Defaults to new if omitted or invalid.
msg
string
Example: msg=helpful

Case-insensitive substring search filter matching text within the review commentary.

Responses

Response samples

Content type
application/json
{
  • "status": "success",
  • "length": 2,
  • "pagination": {
    },
  • "data": [
    ]
}

Submit a new customer review and rating for a book

Creates a new review commentary and numerical star rating for the designated book.

Authentication & Access Control

  • Required Authentication: Bearer JWT token (protect middleware).
  • Role Restriction: Accessible only to customers holding role: 'user' (restrictTo("user")).
  • Email Verification: User account email address must be verified (isEmailVerified: true).

Catalog Validation & Business Rules

  1. Book Existence Verification: Queries MongoDB via Books.findById(bookId). If the target book does not exist in the catalog, the request fails immediately with HTTP 404 Not Found ("Book not exists").
  2. One Review per Customer per Book: The database enforces a compound unique index on { user: 1, book: 1 }. If the authenticated customer has already submitted a review for this book, the creation request is rejected.
  3. Rating Constraints: Rating must be a numerical value between 1 (minimum) and 5 (maximum).

Automated Rating Aggregation Lifecycle

Upon saving a new review, a Mongoose post("save") lifecycle hook triggers:

  • Executes aggregation pipeline Review.calcAvgRating(this.book).
  • Computes the updated cumulative rating count (nRating) and arithmetic average (avgRating).
  • Updates ratingQuantity and ratingAverage fields directly on the corresponding Books catalog document.

Rate Limiting

  • Protected by mutationLimiter: Maximum 10 mutation requests per minute per client IP.
Authorizations:
bearerAuth
path Parameters
bookId
required
string^[0-9a-fA-F]{24}$
Example: 683aab454ae6c56e60594eb7

The 24-character hexadecimal MongoDB ObjectId uniquely identifying the book.

Request Body schema: application/json
required

Review text and numerical rating submitted by the customer.

review
required
string non-empty

Customer's detailed review commentary. Leading and trailing whitespace is trimmed.

rating
required
number [ 1 .. 5 ]

Star rating for the book, ranging from 1 to 5.

Responses

Request samples

Content type
application/json
{
  • "review": "An exceptional, comprehensive guide to clean architecture and readable code.",
  • "rating": 5
}

Response samples

Content type
application/json
{
  • "status": "success",
  • "message": "Review created successfully",
  • "data": {
    }
}

Update the authenticated customer's review and rating for a book

Updates the existing review text commentary and/or star rating submitted by the authenticated customer for the designated book.

Authentication & Access Control

  • Required Authentication: Bearer JWT token (protect middleware).
  • Role Restriction: Accessible only to customers holding role: 'user' (restrictTo("user")).
  • Email Verification: User account email address must be verified (isEmailVerified: true).

Operational Logic

  1. Verifies that bookId is supplied in the request path parameters (!bookId -> HTTP 404 "Book id not found").
  2. Validates book existence via Books.findById(bookId). If the book does not exist in the catalog, returns HTTP 404 "Book not found".
  3. Executes Review.findOneAndUpdate({ book: bookId, user: req.user.id }, req.body, { new: true }).
  4. Automated Rating Resynchronization: A Mongoose post(/^findOneAnd/) middleware hook executes immediately after the update:
    • Calls calcAvgRating(doc.book._id) with the reviewed book's ID.
    • Aggregates all current reviews for the book and synchronizes ratingAverage and ratingQuantity on the Books document.

Rate Limiting

  • Protected by mutationLimiter: Maximum 10 mutation requests per minute per client IP.
Authorizations:
bearerAuth
path Parameters
bookId
required
string^[0-9a-fA-F]{24}$
Example: 683aab454ae6c56e60594eb7

The 24-character hexadecimal MongoDB ObjectId uniquely identifying the book.

Request Body schema: application/json
required

Modified review commentary or revised numerical rating.

review
string non-empty

Updated review commentary.

rating
number [ 1 .. 5 ]

Updated star rating score on a scale from 1 to 5.

Responses

Request samples

Content type
application/json
{
  • "review": "Updated review: Still an absolute classic for any software craftsman.",
  • "rating": 4.5
}

Response samples

Content type
application/json
{
  • "status": "success",
  • "message": "review updated successfully",
  • "data": {
    }
}

Delete the authenticated customer's review for a book

Permanently deletes the customer's review and star rating for the specified book.

Authentication & Access Control

  • Required Authentication: Bearer JWT token (protect middleware).
  • Role Restriction: Accessible only to customers holding role: 'user' (restrictTo("user")).
  • Email Verification: User account email address must be verified (isEmailVerified: true).

Operational Logic

  1. Executes Review.findOneAndDelete({ book: bookId, user: req.user.id }).
  2. Automated Rating Resynchronization: A Mongoose post(/^findOneAnd/) middleware hook executes immediately after deletion:
    • Recalculates the book's remaining review statistics via calcAvgRating(doc.book._id).
    • Updates ratingQuantity and ratingAverage on the Books document.
    • If all reviews for the book have been deleted, automatically resets both ratingAverage and ratingQuantity to 0.

Rate Limiting

  • Protected by generalRateLimiter: Maximum 15 requests per minute per client IP.
Authorizations:
bearerAuth
path Parameters
bookId
required
string^[0-9a-fA-F]{24}$
Example: 683aab454ae6c56e60594eb7

The 24-character hexadecimal MongoDB ObjectId uniquely identifying the book.

Responses

Response samples

Content type
application/json
{
  • "status": "success",
  • "data": null
}

Retrieve all catalog reviews across all books (Admin only)

Provides comprehensive administrative oversight of all customer reviews submitted across the bookstore catalog.

Authentication & Access Control

  • Required Authentication: Bearer JWT token (protect middleware).
  • Role Restriction: Strictly restricted to users holding role: 'admin' (restrictTo("admin")).
  • Email Verification: Admin account email address must be verified (isEmailVerified: true).

Search & Filtering Capabilities

  • Keyword Search (msg): Optional case-insensitive regular expression substring filter ({ review: { $regex: msg, $options: "i" } }) searched across all review bodies in the database.
  • Catalog-wide Scope: Unlike the book-specific review endpoint, this queries all reviews without filtering by a specific book ID.

Sorting Behavior

  • sort=new (default): Sorts descending by -createdAt (most recently submitted reviews first).
  • sort=old: Sorts ascending by createdAt (oldest reviews first).
  • Any unrecognized or omitted sort option automatically defaults to new.

Pagination Rules

  • page: 1-based page index (defaults to 1).
  • limit: Number of records returned per page (defaults to 10).
  • Upper Bound: If limit exceeds 100, the server automatically caps it at 100.
  • Computes skip = (page - 1) * limit.
  • Computes totalPages = Math.ceil(totalItems / limit) and hasNextPage = page < totalPages.

Data Population

  • Automatically populates the author's public name (user: { _id, name }) and book title (book: { _id, title }) via Mongoose pre(/^find/) query middleware.

Rate Limiting

  • Protected by getRateLimiter: Maximum 30 requests per minute per client IP.
Authorizations:
bearerAuth
query Parameters
page
integer >= 1
Default: 1
Example: page=1

1-based page index for pagination. Defaults to 1.

limit
integer [ 1 .. 100 ]
Default: 10
Example: limit=10

Number of review records to return per page. Defaults to 10. Automatically clamped to a maximum of 100 by the server.

sort
string
Default: "new"
Enum: "new" "old"
Example: sort=new

Chronological ordering of reviews:

  • new: Newest reviews first (descending by -createdAt).
  • old: Oldest reviews first (ascending by createdAt). Defaults to new if omitted or invalid.
msg
string
Example: msg=practical

Case-insensitive substring search filter matching text within the review commentary.

Responses

Response samples

Content type
application/json
{
  • "status": "success",
  • "message": "reviews found successfully",
  • "pagination": {
    },
  • "length": 10,
  • "data": [
    ]
}

Retrieve current user's review for a book (with Redis caching)

Retrieves the specific review and rating written by the authenticated customer for the designated book, utilizing a high-performance Redis cache-aside caching pattern.

Authentication & Access Control

  • Required Authentication: Bearer JWT token (protect middleware).
  • Role Restriction: Accessible only to customers holding role: 'user' (restrictTo("user")).
  • Email Verification: User account email address must be verified (isEmailVerified: true).
  • Parameter Validation: Middleware validateId("bookId") validates that bookId is a valid 24-character hexadecimal MongoDB ObjectId before controller execution.

High-Performance Redis Cache-Aside Architecture

  1. Cache Lookup: Checks Redis for key user:{userId}:book:{bookId} using client.get(...).
  2. Cache Hit:
    • Returns cached serialized review immediately from Redis memory without querying MongoDB.
    • Responds with HTTP 200 OK: { status: "success", message: "review found successfully", data: JSON.parse(reviewData) }.
  3. Cache Miss:
    • Queries MongoDB for an existing review via Review.findOne({ book: bookId, user: req.user.id }).
    • If no review exists, aborts with HTTP 404 Not Found ("Review not found").
    • If found:
      • Serializes the review document and writes it to Redis key user:{userId}:book:{bookId}.
      • Responds with HTTP 200 OK: { status: "success", data: review }.

Rate Limiting

  • Protected by getRateLimiter: Maximum 30 requests per minute per client IP.
Authorizations:
bearerAuth
path Parameters
bookId
required
string^[0-9a-fA-F]{24}$
Example: 683aab454ae6c56e60594eb7

The 24-character hexadecimal MongoDB ObjectId uniquely identifying the book.

Responses

Response samples

Content type
application/json
Example
{
  • "status": "success",
  • "message": "review found successfully",
  • "data": {
    }
}

users

User account management, profile settings, order history, and favourites collection.

Includes:

  • Retrieving authenticated customer profile (/users/me)
  • Updating user account information and delivery address (/users/updateMe)
  • Retrieving past order history (/users/orders)
  • Managing book favourites and wishlist items (/users/favBooks)
  • Administrator user catalog querying with multi-field regex filters and pagination (/users/all)
  • Administrator single user lookup by ID (/users/{userId})

Retrieve the authenticated user's profile

Retrieves the complete profile and personal information of the currently authenticated user.

Authentication & Access Control

  • Required Authentication: Bearer JWT token in the Authorization header (protect middleware).
  • Email Verification: User account email address must be verified (isEmailVerified: true).

Account Status & Soft-Deactivation Filter

  • Database queries run through a Mongoose pre(/^find/) middleware that automatically excludes deactivated accounts ({ isActive: { $ne: false } }).
  • If the account has been deactivated by an administrator, the request aborts with HTTP 404 Not Found ("user does not exists").

Rate Limiting

  • Protected by getRateLimiter: Maximum 30 requests per minute per client IP.
Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "status": "success",
  • "message": "user found successfully",
  • "data": {
    }
}

Update the authenticated user's profile information

Updates personal profile information, contact number, gender, date of birth, or physical shipping address for the currently authenticated user.

Authentication & Access Control

  • Required Authentication: Bearer JWT token (protect middleware).
  • Email Verification: User account email address must be verified (isEmailVerified: true).

Operational Behavior & Validation

  • Input Validation (validateUser middleware):
    • name: Optional, must be a string ("Name must be a string").
    • dateOfBirth: Optional, must be a valid ISO date ("Date of birth must be a date").
    • phoneNumber: Optional, must be a numeric value ("Phone Number must be a number").
    • gender: Optional, must be one of ["male", "female", "others"] ("Gender must be male, female, or others").
    • address: Optional object ("Address must be an object").
    • address.line, address.street, address.city, address.state, address.country: Optional, must be strings.
    • address.zipCode: Optional, must be a numeric value ("Zip Code must be a number").
    • Any validation failure returns HTTP 400 Bad Request with the first validation error message.
  • Database Update:
    • Executes User.findByIdAndUpdate(req.user.id, { name, dateOfBirth, phoneNumber, gender, address }).
    • If the update operation cannot be fulfilled, returns HTTP 400 Bad Request ("user is not updated").
    • Upon successful update, responds with HTTP 201 Created returning the updated user document in data.

Rate Limiting

  • Protected by mutationLimiter: Maximum 10 mutation requests per minute per client IP.
Authorizations:
bearerAuth
Request Body schema: application/json
required

Personal profile attributes and delivery address fields to modify.

name
string >= 2 characters

Updated full name of the user.

phoneNumber
integer

Updated 10-digit primary telephone contact number.

gender
string
Enum: "male" "female" "others"

Updated gender identity.

dateOfBirth
string <date>

Updated date of birth (YYYY-MM-DD).

object (Address)

Physical address associated with a user.

Responses

Request samples

Content type
application/json
{
  • "name": "Keyur Panchal",
  • "phoneNumber": 9876543210,
  • "gender": "male",
  • "dateOfBirth": "2005-06-08",
  • "address": {
    }
}

Response samples

Content type
application/json
{
  • "status": "success",
  • "message": "user updated successfully",
  • "data": {
    }
}

Retrieve past order history for the authenticated user

Retrieves the complete list of historical bookstore orders placed by the currently authenticated customer.

Authentication & Access Control

  • Required Authentication: Bearer JWT token (protect middleware).
  • Email Verification: User account email address must be verified (isEmailVerified: true).

Query Behavior

  • Queries MongoDB Order collection matching { user: req.user.id }.
  • Returns each order with itemized book purchases, quantities, calculated monetary totals, shipping address snapshot, order fulfillment status, and Stripe payment metadata.

Rate Limiting

  • Protected by getRateLimiter: Maximum 30 requests per minute per client IP.
Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "status": "success",
  • "length": 1,
  • "data": [
    ]
}

Add a book to the authenticated user's favourites

Appends a specific book to the authenticated user's personal favourites collection.

Authentication & Access Control

  • Required Authentication: Bearer JWT token (protect middleware).
  • Email Verification: User account email address must be verified (isEmailVerified: true).

Business Rules & Duplicate Prevention

  1. Parameter Validation: Requires a valid bookId in the JSON request body. If omitted, returns HTTP 404 Not Found ("please provide book id").
  2. Duplicate Check: Inspects user.faviourites. If the book already resides in the customer's favourites list, the request is rejected with HTTP 400 Bad Request ("Book is already in favourites").
  3. Persistence: Appends the book's 24-character hexadecimal ObjectId to the faviourites array and saves the modified user record.

Rate Limiting

  • Protected by mutationLimiter: Maximum 10 mutation requests per minute per client IP.
Authorizations:
bearerAuth
Request Body schema: application/json
required

Object containing the 24-character MongoDB ObjectId of the book to favourite.

bookId
required
string^[0-9a-fA-F]{24}$

24-character hexadecimal MongoDB ObjectId of the book to add to favourites.

Responses

Request samples

Content type
application/json
{
  • "bookId": "683aab454ae6c56e60594eb7"
}

Response samples

Content type
application/json
{
  • "status": "success",
  • "message": "Book added to favourites",
  • "data": {
    }
}

Retrieve all registered users with multi-field search and pagination (Admin only)

Retrieves a paginated list of registered users across the platform for administrative auditing, customer support, and account management.

Authentication & Access Control

  • Required Authentication: Bearer JWT token (protect middleware).
  • Role Restriction: Strictly restricted to users holding role: 'admin' (restrictTo("admin")).
  • Email Verification: Admin account email address must be verified (isEmailVerified: true).
  • Name Search (name): Case-insensitive regular expression substring match ({ name: { $regex: name, $options: "i" } }).
  • Email Search (email): Case-insensitive regular expression substring match ({ email: { $regex: email, $options: "i" } }).
  • Phone Search (phone): Matches against phone number digits by converting numeric phone to string via MongoDB $expr with $regexMatch.
  • Filters can be combined simultaneously.

Sorting Behavior

  • sort=new (default): Sorts descending by -createdAt (most recently registered accounts first).
  • sort=old: Sorts ascending by createdAt (earliest registered accounts first).
  • Unrecognized or omitted sort parameters default to new.

Pagination Rules

  • page: 1-based page index (defaults to 1).
  • limit: Number of records returned per page (defaults to 10).
  • Upper Bound: If limit exceeds 100, the server automatically caps it at 100.
  • Computes skip = (page - 1) * limit.
  • Computes totalPages = Math.ceil(totalItems / limit) and hasNextPage = page < totalPages.
  • Dynamic response message: "all users found successfully" if records exist, otherwise "users not found".

Active User Query Filter

  • Automatically excludes deactivated accounts ({ isActive: { $ne: false } }) via Mongoose pre(/^find/) hook.

Rate Limiting

  • Protected by getRateLimiter: Maximum 30 requests per minute per client IP.
Authorizations:
bearerAuth
query Parameters
name
string
Example: name=Keyur

Case-insensitive substring search matching user's full name.

email
string
Example: email=gmail.com

Case-insensitive substring search matching user's email address.

phone
string
Example: phone=9876

Substring digit pattern matching user's telephone number.

sort
string
Default: "new"
Enum: "new" "old"
Example: sort=new

Ordering criterion for user accounts:

  • new: Newest users first (descending by -createdAt).
  • old: Oldest users first (ascending by createdAt). Defaults to new if omitted or invalid.
page
integer >= 1
Default: 1
Example: page=1

1-based page index for pagination. Defaults to 1.

limit
integer [ 1 .. 100 ]
Default: 10
Example: limit=10

Number of user records returned per page. Defaults to 10. Automatically clamped to a maximum of 100 by the server.

Responses

Response samples

Content type
application/json
{
  • "status": "success",
  • "length": 2,
  • "pagination": {
    },
  • "message": "all users found successfully",
  • "allUser": [
    ]
}

Retrieve a user account by unique ID (Admin only)

Retrieves complete personal profile and account metadata for an individual user by their unique MongoDB ObjectId.

Authentication & Access Control

  • Required Authentication: Bearer JWT token (protect middleware).
  • Role Restriction: Strictly restricted to users holding role: 'admin' (restrictTo("admin")).
  • Email Verification: Admin account email address must be verified (isEmailVerified: true).
  • Parameter Validation: Middleware validateId("userId") validates that userId is a valid 24-character hexadecimal MongoDB ObjectId before execution.

Active Account Status

  • Inactive or suspended user accounts are automatically excluded by Mongoose query middleware ({ isActive: { $ne: false } }). If the user does not exist or has been suspended, returns HTTP 404 Not Found ("user does not exists").

Rate Limiting

  • Protected by getRateLimiter: Maximum 30 requests per minute per client IP.
Authorizations:
bearerAuth
path Parameters
userId
required
string^[0-9a-fA-F]{24}$
Example: 683aa9c34ae6c56e60594eb2

The 24-character hexadecimal MongoDB ObjectId uniquely identifying the user account.

Responses

Response samples

Content type
application/json
{
  • "status": "success",
  • "message": "user found successfully",
  • "data": {
    }
}

wishlist

Customer book wishlist and saved items management endpoints.

Includes:

  • Retrieving all saved books in customer's wishlist with populated book catalog details (/wishlist)
  • Adding books to personal wishlist with real-time catalog existence and duplicate validation (/wishlist/{bookId})
  • Removing books from customer wishlist (/wishlist/{bookId})

Retrieve all books saved in the authenticated user's wishlist

Retrieves the complete list of books saved to the authenticated customer's wishlist, with full catalog metadata populated for each book.

Authentication & Access Control

  • Required Authentication: Bearer JWT token in the Authorization header (protect middleware).
  • Email Verification: User account email address must be verified (isEmailVerified: true).

Catalog Data Population

  • Queries the Wishlist collection matching { user: req.user._id }.
  • Automatically populates the referenced book with essential catalog attributes: title, author, price, coverImage, category, ratingAverage, and current inventory stock.

Rate Limiting

  • Protected by getRateLimiter: Maximum 30 requests per minute per client IP.
Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "status": "success",
  • "message": "All wishlist items are successfully found",
  • "results": 2,
  • "data": [
    ]
}

Add a book to the authenticated user's wishlist

Saves a designated book to the authenticated customer's personal wishlist for future purchase.

Authentication & Access Control

  • Required Authentication: Bearer JWT token (protect middleware).
  • Email Verification: User account email address must be verified (isEmailVerified: true).
  • Parameter Validation: Middleware validateId("bookId") verifies that bookId is a syntactically valid 24-character hexadecimal MongoDB ObjectId.

Verification & Business Rules

  1. Catalog Existence Verification: Queries MongoDB via Books.findById(bookId). If the target book does not exist in the catalog, the request fails immediately with HTTP 404 Not Found ("Book not found").
  2. Duplicate Prevention: Queries Wishlist.findOne({ user: req.user._id, book: bookId }). If the book already resides in the customer's wishlist, the request is rejected with HTTP 400 Bad Request ("Book is already in your wishlist").
  3. Database Uniqueness Constraint: The Wishlist schema enforces a compound unique index { user: 1, book: 1 } guaranteeing concurrency-safe deduplication.

Rate Limiting

  • Protected by mutationLimiter: Maximum 10 mutation requests per minute per client IP.
Authorizations:
bearerAuth
path Parameters
bookId
required
string^[0-9a-fA-F]{24}$
Example: 683aab454ae6c56e60594eb7

The 24-character hexadecimal MongoDB ObjectId uniquely identifying the book.

Responses

Response samples

Content type
application/json
{
  • "status": "success",
  • "message": "Book successfully added to wishlist",
  • "data": {
    }
}

Remove a book from the authenticated user's wishlist

Removes a designated book from the authenticated customer's wishlist.

Authentication & Access Control

  • Required Authentication: Bearer JWT token (protect middleware).
  • Email Verification: User account email address must be verified (isEmailVerified: true).
  • Parameter Validation: Middleware validateId("bookId") verifies that bookId is a syntactically valid 24-character hexadecimal MongoDB ObjectId.

Operational Logic

  1. Executes Wishlist.findOneAndDelete({ user: req.user._id, book: bookId }).
  2. If no matching wishlist entry is found for this customer and book, the server responds with HTTP 404 Not Found ("Book is not in your wishlist").
  3. Upon successful removal, responds with HTTP 200 OK.

Rate Limiting

  • Protected by generalRateLimiter: Maximum 15 requests per minute per client IP.
Authorizations:
bearerAuth
path Parameters
bookId
required
string^[0-9a-fA-F]{24}$
Example: 683aab454ae6c56e60594eb7

The 24-character hexadecimal MongoDB ObjectId uniquely identifying the book.

Responses

Response samples

Content type
application/json
{
  • "status": "success",
  • "message": "Book successfully removed from wishlist"
}