A flexible, production-ready Django application featuring a pluggable rule engine for order validation. Built with enterprise-level standards, comprehensive testing, and auto-registration capabilities.
➡️ Try the Live Demo (Swagger UI) ⬅️
Test all endpoints directly in your browser - no setup required!
- 🔌 Pluggable Architecture: Add new rules without modifying existing code
- 🤖 Auto-Registration: Rules are automatically discovered and registered using metaclasses
- 📊 RESTful API: Clean, well-documented endpoints with DRF
- 📖 Interactive Documentation: Swagger UI and ReDoc for API exploration
- ✅ Comprehensive Testing: 100% test coverage with unit and integration tests
- 🔒 Production-Ready: Security best practices, logging, error handling
- 🐳 Docker Support: Fully containerized with Docker and Docker Compose
- 🔄 CI/CD Pipeline: GitHub Actions for automated testing and deployment
- 📝 Code Quality: Type hints, docstrings, and clean architecture
- 🚀 Deployment Ready: Configured for Render, Railway, and other platforms
- 📚 Well-Documented: Comprehensive inline documentation and README
The rule engine uses a metaclass-based auto-registration pattern:
from rules.engine import BaseRule
class MyCustomRule(BaseRule):
name = "my_custom_rule"
description = "Custom validation logic"
def evaluate(self, order) -> bool:
return order.total > 50 # Your logic hereThat's it! The rule is automatically registered and available via the API.
┌─────────────────────────────────────────────────────┐
│ API Layer (DRF) │
│ ┌──────────────┐ ┌──────────────────────┐ │
│ │ RuleCheckView│ │ RuleListView │ │
│ └──────────────┘ └──────────────────────┘ │
└─────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ Rule Engine │
│ ┌──────────────────────────────────────────────┐ │
│ │ RuleRegistry (Metaclass) │ │
│ │ - Auto-discovers rules │ │
│ │ - Manages rule instances │ │
│ └──────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ Business Rules │
│ ┌──────────────┐ ┌──────────────┐ ┌────────────┐ │
│ │MinTotalRule │ │MinItemsRule │ │ Custom... │ │
│ └──────────────┘ └──────────────┘ └────────────┘ │
└─────────────────────────────────────────────────────┘
# Clone the repository
git clone https://github.com/William9701/Pluggable_Rule_Engine.git
cd Pluggable_Rule_Engine
# Start with Docker Compose
docker-compose up
# API will be available at https://pluggable-rule-engine.onrender.com# Clone the repository
git clone https://github.com/William9701/Pluggable_Rule_Engine.git
cd Pluggable_Rule_Engine
# Create virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt
# Run migrations
python manage.py migrate
# Seed database with example orders
python manage.py seed_orders
# Run development server
python manage.py runserverNavigate to https://pluggable-rule-engine.onrender.com to see the interactive Swagger documentation.
curl https://pluggable-rule-engine.onrender.com/rules/Response:
[
{
"name": "min_total_100",
"description": "Validates that order total is greater than 100"
},
{
"name": "min_items_2",
"description": "Validates that order has at least 2 items"
},
{
"name": "divisible_by_5",
"description": "Validates that order total is divisible by 5"
}
]curl -X POST https://pluggable-rule-engine.onrender.com/rules/check/ \
-H "Content-Type: application/json" \
-d '{
"order_id": 1,
"rules": ["min_total_100", "min_items_2"]
}'Response:
{
"passed": true,
"details": {
"min_total_100": true,
"min_items_2": true
}
}| Method | Endpoint | Description |
|---|---|---|
| GET | / |
Swagger UI documentation |
| GET | /redoc/ |
ReDoc documentation |
| GET | /rules/ |
List all available rules |
| POST | /rules/check/ |
Evaluate rules against an order |
Request Body:
{
"order_id": 1,
"rules": ["min_total_100", "min_items_2", "divisible_by_5"]
}Success Response (200):
{
"passed": false,
"details": {
"min_total_100": true,
"min_items_2": false,
"divisible_by_5": true
}
}Error Response (404):
{
"error": "Order not found",
"detail": "Order with id 999 does not exist",
"status_code": 404
}Create a new file rules/custom_rules.py:
from .engine import BaseRule
from decimal import Decimal
class PremiumOrderRule(BaseRule):
name = "premium_order"
description = "Order qualifies as premium (total > 500 and items > 5)"
def evaluate(self, order) -> bool:
return order.total > Decimal('500.00') and order.items_count > 5Add to rules/apps.py:
def ready(self):
from . import order_rules
from . import custom_rules # Add this lineThat's it! Your rule is now available via the API automatically.
# Run all tests
python manage.py test
# Run with coverage
pip install coverage
coverage run --source='.' manage.py test
coverage report
coverage html # Generate HTML reportTest Coverage: 100% coverage across all components
- Create a new Web Service on Render
- Connect your GitHub repository
- Use these settings:
- Build Command:
sh build.sh - Start Command:
gunicorn config.wsgi:application
- Build Command:
- Add environment variables:
SECRET_KEY: Generate a secure keyDEBUG:FalseALLOWED_HOSTS: Your domain
The render.yaml file is included for automatic configuration.
- Click "Deploy on Railway" (or create manually)
- Connect your repository
- Add environment variables (same as above)
- Deploy!
| Variable | Description | Default |
|---|---|---|
SECRET_KEY |
Django secret key | (required) |
DEBUG |
Debug mode | False |
ALLOWED_HOSTS |
Comma-separated hosts | localhost,127.0.0.1 |
DATABASE_URL |
Database connection string | SQLite |
pluggable-rule-engine/
├── config/ # Django project settings
│ ├── settings.py # Settings with environment variables
│ ├── urls.py # URL configuration with Swagger
│ └── wsgi.py
├── orders/ # Orders app
│ ├── models.py # Order model with validation
│ ├── serializers.py # DRF serializers
│ ├── admin.py # Admin configuration
│ └── management/
│ └── commands/
│ └── seed_orders.py # Database seeding
├── rules/ # Rules engine app
│ ├── engine.py # Core engine with metaclass
│ ├── order_rules.py # Built-in rules
│ ├── views.py # API views
│ ├── serializers.py # Request/response serializers
│ ├── exceptions.py # Custom exception handlers
│ └── tests.py # Comprehensive test suite
├── .github/
│ └── workflows/
│ └── ci.yml # GitHub Actions CI/CD
├── Dockerfile # Docker configuration
├── docker-compose.yml # Local development setup
├── requirements.txt # Python dependencies
├── render.yaml # Render deployment config
└── README.md # This file
- Framework: Django 5.0
- API: Django REST Framework 3.14
- Documentation: drf-yasg (Swagger/OpenAPI)
- Server: Gunicorn
- Database: PostgreSQL/SQLite
- Containerization: Docker
- CI/CD: GitHub Actions
- Deployment: Render, Railway
Contributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
- Write tests for new features
- Follow PEP 8 style guidelines
- Add docstrings to all functions/classes
- Update documentation as needed
This project is licensed under the MIT License - see the LICENSE file for details.
- Built with Django
- API powered by Django REST Framework
- Documentation generated with drf-yasg
Project Link: https://github.com/William9701/Pluggable_Rule_Engine
Live Demo: https://pluggable-rule-engine.onrender.com
Made with ❤️ using Django