Skip to content

Baza-ar/Catalog

Repository files navigation

Bazaar Catalog API

FastAPI Python PostgreSQL Docker OpenTelemetry

The Bazaar Catalog API is a RESTful microservice responsible for managing the entire product lifecycle within the Bazaar ecosystem. Built on FastAPI and backed by PostgreSQL, it provides full CRUD operations for products, image management through Cloudinary, stock transaction handling, full-text search with relevance ranking, and asynchronous event processing via RabbitMQ. The service integrates with OpenTelemetry for distributed tracing in production environments.


Table of Contents

  1. Core Features
  2. System Architecture
  3. Technology Stack
  4. Project Structure
  5. Environment Configuration
  6. Getting Started
  7. API Reference
  8. Testing
  9. Stress & Performance Testing (k6)

Core Features

  • Full Product Lifecycle Management:
    • Create, read, update, and delete products with validation and ownership enforcement.
    • Support for multi-image uploads per product with ordered display, powered by Cloudinary CDN.
    • Paginated product listings with advanced filtering by category, price range, stock availability, and active status.
  • Full-Text Search with Relevance Ranking:
    • Leverages PostgreSQL tsvector with weighted columns (title: A, description: B) for relevance-based search.
    • Trigram indexing (pg_trgm) on product titles enables fuzzy matching and typo-tolerant queries.
    • Supports multiple sort orders: by creation date, price, or relevance score.
  • Stock & Transaction Processing:
    • Exposes endpoints for stock deduction and restoration during order workflows.
    • Subscribes to RabbitMQ events (catalog.transactions.restore) to asynchronously restore inventory when orders are cancelled.
  • Admin Backoffice Operations:
    • Dedicated admin endpoints to list, filter, and moderate products across all sellers.
    • Admins can block/unblock products, with a full state history audit trail tracking every status change.
  • Seller Dashboard & Analytics:
    • Sellers can view their own products with private filters (active, inactive, out-of-stock).
    • Stats endpoint provides aggregated counts of total, active, and out-of-stock products per seller.
    • Top-selling product rankings available both globally and per seller.
  • Shareable Product Deep Links:
    • Generates shareable URLs that redirect to the mobile app via custom URI scheme (bazaar://product/{id}).
    • Gracefully handles unavailable products with a user-friendly fallback page.
  • Inter-Service Communication:
    • Validates seller status against the User Service before write operations (blocks requests from banned users).
    • Provides cart-optimized product information endpoint for the Cart Service.
  • Observability & Health Checks:
    • Liveness (/livez) and Readiness (/readyz) probes for container orchestration.
    • Readiness checks verify both database connectivity and Cloudinary availability.
    • Full OpenTelemetry instrumentation in production and stress environments via opentelemetry-instrument.
    • Structured logging with Loguru for consistent, queryable log output.

System Architecture

The Catalog Service sits behind the Bazaar API Gateway and interacts with multiple services within the ecosystem:

graph TD
    Gateway([API Gateway]) -->|"X-User-Id, X-User-Role"| CatalogService[Catalog Service - FastAPI]

    subgraph Catalog Microservice
        CatalogService -->|CRUD Operations| DB[(PostgreSQL 15)]
        CatalogService -->|Image Upload / Delete| Cloudinary[Cloudinary CDN]
        CatalogService -->|Validate Seller Status| UserService[User Service]
    end

    RabbitMQ[RabbitMQ] -->|"catalog.transactions.restore"| CatalogService
    OrdersService([Orders Service]) -->|Publish Events| RabbitMQ
    CartService([Cart Service]) -->|"GET /catalog/products/cart/info"| CatalogService
Loading

Note

The Catalog Service relies on trust-based authorization. It extracts user identity from the X-User-Id and X-User-Role headers injected by the API Gateway — it never handles JWT parsing directly.


Technology Stack

Layer Technology
Framework FastAPI 0.135.1 (Uvicorn ASGI server)
Language Python 3.11
Database PostgreSQL 15, SQLAlchemy 2.0, Alembic (migrations)
Image Storage Cloudinary (CDN-hosted product images)
Message Broker RabbitMQ (via aio-pika, async AMQP)
Validation Pydantic v2, pydantic-settings
Telemetry OpenTelemetry SDK + FastAPI instrumentation
Logging Loguru
Testing Pytest, pytest-cov (≥ 70% coverage), pytest-timeout
Deployment Docker, Docker Compose, bazaar-network
CI/CD GitHub Actions (automated test pipeline)

Environment Configuration

Create a .env file in the root directory based on the .env.example template:

cp .env.example .env

Required Configuration Properties

Variable Description Default / Example
Server
PORT HTTP port the service listens on 8081
HOST Bind address for the server 0.0.0.0
ENVIRONMENT Runtime mode (development, testing, production, stress) development
Database
DATABASE_HOST PostgreSQL hostname postgres-catalog
DATABASE_NAME Database name api-catalog-db
DATABASE_INNER_PORT Internal PostgreSQL port (container) 5432
DATABASE_OUTER_PORT Mapped PostgreSQL port on host 5432
DATABASE_USER Database user api-catalog-user
DATABASE_PASSWORD Database password hard-to-guess-password
Test Database
DATABASE_TEST_HOST Test PostgreSQL hostname postgres-test
DATABASE_TEST_NAME Test database name api-catalog-test-db
DATABASE_TEST_PORT Test PostgreSQL port 5432
DATABASE_TEST_USER Test database user api-catalog-test-user
DATABASE_TEST_PASSWORD Test database password hard-to-guess-password
Cloudinary
CLOUDINARY_CLOUD_NAME Cloudinary cloud name for image hosting cloudinary-name
CLOUDINARY_API_KEY Cloudinary API key your-cloudinary-api-key
CLOUDINARY_API_SECRET Cloudinary API secret your-cloudinary-api-secret
Inter-Service URLs
API_USER_URL Base URL of the User Microservice http://user-service:8080
API_ORDER_URL Base URL of the Orders Microservice http://orders-service:8080
API_GATEWAY_URL Base URL of the API Gateway http://localhost:8000
Message Broker
RABBIT_MQ_URL RabbitMQ connection string (AMQP) amqps://guest:guest@localhost:5671
Telemetry
OTEL_SERVICE_NAME Service label reported in OpenTelemetry traces api-catalog
OTEL_EXPORTER_OTLP_PROTOCOL OTLP exporter protocol http/protobuf
OTEL_EXPORTER_OTLP_ENDPOINT OpenTelemetry collector endpoint your-otlp-endpoint
OTEL_EXPORTER_OTLP_HEADERS Authentication headers for the OTLP exporter your-otel-headers
Deep Links
MOBILE_APP_URL Custom URI scheme for mobile deep links bazaar://product

Getting Started

Prerequisites

  • Docker & Docker Compose

For local development without Docker:

  • Python 3.11 or later
  • pip (Python package manager)
  • PostgreSQL 15
python -m venv venv

source venv/bin/activate   # Linux / macOS
venv\Scripts\activate      # Windows

pip install -r requirements.txt

Running with Docker Compose

  1. Create the shared Docker network (if not already created):

    docker network create bazaar-network
  2. Build and start the service:

    docker compose up --build -d

    The service starts on port 8081 by default. On startup, Alembic automatically runs all pending database migrations.

  3. Verify the service is healthy:

    curl http://localhost:8081/livez

    Expected response:

    {"status": "OK"}

    For a full readiness check (database + Cloudinary):

    curl http://localhost:8081/readyz

    Expected response:

    {"status": "READY"}

Stopping the Service

To tear down the containers and remove volumes:

docker compose down -v

Viewing Logs

To follow the application logs in real time:

docker compose logs -f catalog-service

API Reference

Interactive API documentation (Swagger UI) is available once the application runs at:

  • Swagger UI: http://localhost:8081/docs#/

Or if you use the service in the cloud, it is available at:

  • Swagger UI: https://catalog-izb7.onrender.com/docs#/

Testing

The test suite uses Pytest with a minimum code coverage threshold of 70%. Tests run against an isolated PostgreSQL instance managed by Docker Compose.

Running Tests with the Script

The simplest way to run the full test suite:

chmod +x run_tests.sh    # Only needed once

./run_tests.sh

This script handles the full lifecycle: building the test containers, executing the tests with coverage reporting, and tearing down the environment.

Running Tests Manually

If you prefer to manage the lifecycle yourself:

  1. Start the test environment:

    docker compose -f docker-compose.test.yml up --build -d
  2. Execute the test suite:

    docker exec fastapi_test_runner pytest -vv -s --timeout=2 --cov=src --cov-report=term-missing --cov-fail-under=70
  3. Tear down the test environment:

    docker compose -f docker-compose.test.yml down -v

CI Pipeline

The project includes a GitHub Actions workflow (.github/workflows/test.yml) that automatically runs the test suite on every push. The pipeline provisions a PostgreSQL service container, installs dependencies, and enforces the 70% coverage threshold.


Stress & Performance Testing (k6)

To run k6 stress tests, the service must be started in stress mode:

  1. Configure environment variables — set ENVIRONMENT=stress in your .env file. In stress mode, Cloudinary uploads are mocked for consistent benchmarking.

  2. Start the service:

    docker compose up --build
  3. Stop the service:

    docker compose down -v

Important

Never use production credentials or databases for stress testing. If you encounter any issues, reach out to the team.

About

This module handles the users products for the Bazaar platform

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages