|
| 1 | +# Flask InputFilter - AI Agent Guide |
| 2 | + |
| 3 | +A Flask extension for validating and filtering input data with comprehensive type support. |
| 4 | + |
| 5 | +## Quick Overview |
| 6 | + |
| 7 | +Flask InputFilter provides a declarative way to validate and filter incoming data in Flask applications. It supports both traditional method-based and modern decorator-based field definitions with full type hints and Cython optimization. |
| 8 | + |
| 9 | +## Installation |
| 10 | + |
| 11 | +```bash |
| 12 | +pip install flask-inputfilter |
| 13 | +# or |
| 14 | +uv add flask-inputfilter |
| 15 | +# or |
| 16 | +poetry add flask-inputfilter |
| 17 | +``` |
| 18 | + |
| 19 | +## Core Concepts |
| 20 | + |
| 21 | +### 1. InputFilter Classes |
| 22 | +Create validation schemas by inheriting from `InputFilter`: |
| 23 | + |
| 24 | +```python |
| 25 | +from flask_inputfilter import InputFilter, field |
| 26 | +from flask_inputfilter.filters import ToIntegerFilter, StringTrimFilter |
| 27 | +from flask_inputfilter.validators import IsIntegerValidator, LengthValidator |
| 28 | + |
| 29 | +class UserInputFilter(InputFilter): |
| 30 | + # Modern decorator syntax (recommended) |
| 31 | + name: str = field( |
| 32 | + required=True, |
| 33 | + filters=[StringTrimFilter()], |
| 34 | + validators=[LengthValidator(min_length=2, max_length=50)] |
| 35 | + ) |
| 36 | + |
| 37 | + age: int = field( |
| 38 | + required=True, |
| 39 | + filters=[ToIntegerFilter()], |
| 40 | + validators=[IsIntegerValidator()] |
| 41 | + ) |
| 42 | + |
| 43 | + # Global filters/validators apply to all fields |
| 44 | + _global_filters = [StringTrimFilter()] |
| 45 | + _global_validators = [] |
| 46 | +``` |
| 47 | + |
| 48 | +### 2. Usage in Flask Routes |
| 49 | + |
| 50 | +```python |
| 51 | +from flask import Flask, request, jsonify |
| 52 | + |
| 53 | +app = Flask(__name__) |
| 54 | + |
| 55 | +@app.route('/users', methods=['POST']) |
| 56 | +def create_user(): |
| 57 | + input_filter = UserInputFilter() |
| 58 | + input_filter.set_data(request.get_json()) |
| 59 | + |
| 60 | + if not input_filter.is_valid(): |
| 61 | + return jsonify({'errors': input_filter.get_error_messages()}), 400 |
| 62 | + |
| 63 | + validated_data = input_filter.get_values() |
| 64 | + # Process validated_data... |
| 65 | + return jsonify(validated_data) |
| 66 | +``` |
| 67 | + |
| 68 | +## Available Components |
| 69 | + |
| 70 | +### Filters (Data Transformation) |
| 71 | +- **String**: `ToUpperFilter`, `ToLowerFilter`, `StringTrimFilter`, `ToCamelCaseFilter` |
| 72 | +- **Type Conversion**: `ToIntegerFilter`, `ToFloatFilter`, `ToBooleanFilter`, `ToDateFilter` |
| 73 | +- **Data Structures**: `ToDataclassFilter`, `ToTypedDictFilter`, `ArrayExplodeFilter` |
| 74 | +- **Images**: `ToBase64ImageFilter`, `ToImageFilter`, `Base64ImageResizeFilter` |
| 75 | +- **Cleaning**: `ToAlphaNumericFilter`, `ToDigitsFilter`, `WhitelistFilter`, `BlacklistFilter` |
| 76 | + |
| 77 | +### Validators (Data Validation) |
| 78 | +- **Type Checking**: `IsStringValidator`, `IsIntegerValidator`, `IsFloatValidator`, `IsBooleanValidator` |
| 79 | +- **Format**: `IsEmailValidator`, `IsUrlValidator`, `IsUuidValidator`, `IsJsonValidator` |
| 80 | +- **Ranges**: `LengthValidator`, `RangeValidator`, `ArrayLengthValidator` |
| 81 | +- **Dates**: `IsDateValidator`, `DateRangeValidator`, `IsFutureDateValidator` |
| 82 | +- **Images**: `IsImageValidator`, `IsHorizontalImageValidator`, `IsVerticalImageValidator` |
| 83 | +- **Logic**: `AndValidator`, `OrValidator`, `NotValidator`, `XorValidator` |
| 84 | + |
| 85 | +### Conditions (Inter-field Validation) |
| 86 | +- **Requirement**: `RequiredIfCondition`, `ExactlyOneOfCondition` |
| 87 | +- **Logic**: `OneOfCondition`, `NOfCondition`, `ExactlyNOfCondition` |
| 88 | +- **Comparison**: `EqualCondition`, `NotEqualCondition` |
| 89 | + |
| 90 | +## Project Structure |
| 91 | + |
| 92 | +``` |
| 93 | +flask_inputfilter/ |
| 94 | +├── __init__.py # Main exports |
| 95 | +├── input_filter.py # Core InputFilter class |
| 96 | +├── py.typed # PEP 561 type support |
| 97 | +├── conditions/ # Inter-field validation logic |
| 98 | +├── filters/ # Data transformation components |
| 99 | +├── validators/ # Data validation components |
| 100 | +├── enums/ # Predefined enums |
| 101 | +├── exceptions/ # Custom exceptions |
| 102 | +├── models/ # Base classes and data models |
| 103 | +├── mixins/ # Reusable mixins |
| 104 | +└── declarative/ # Decorator-based field definition |
| 105 | +``` |
| 106 | + |
| 107 | +## Development Commands |
| 108 | + |
| 109 | +```bash |
| 110 | +# Install dependencies |
| 111 | +pip install -e ".[dev]" |
| 112 | + |
| 113 | +# Run tests |
| 114 | +pytest |
| 115 | + |
| 116 | +# Lint code |
| 117 | +ruff check |
| 118 | + |
| 119 | +# Format code |
| 120 | +ruff format |
| 121 | + |
| 122 | +# Type checking |
| 123 | +mypy flask_inputfilter |
| 124 | + |
| 125 | +# Build documentation |
| 126 | +cd docs && make html |
| 127 | + |
| 128 | +# Build package |
| 129 | +python -m build |
| 130 | +``` |
| 131 | + |
| 132 | +## Advanced Features |
| 133 | + |
| 134 | +### Custom Components |
| 135 | +```python |
| 136 | +from flask_inputfilter.models.base_filter import BaseFilter |
| 137 | +from flask_inputfilter.models.base_validator import BaseValidator |
| 138 | + |
| 139 | +class CustomFilter(BaseFilter): |
| 140 | + def filter(self, value, context=None): |
| 141 | + # Your transformation logic |
| 142 | + return transformed_value |
| 143 | + |
| 144 | +class CustomValidator(BaseValidator): |
| 145 | + def is_valid(self, value, context=None): |
| 146 | + # Your validation logic |
| 147 | + return True # or False |
| 148 | +``` |
| 149 | + |
| 150 | +### External API Integration |
| 151 | +```python |
| 152 | +from flask_inputfilter.models.external_api_config import ExternalApiConfig |
| 153 | + |
| 154 | +class UserInputFilter(InputFilter): |
| 155 | + user_id: int = field( |
| 156 | + external_api=ExternalApiConfig( |
| 157 | + url="https://api.example.com/users/{user_id}", |
| 158 | + method="GET", |
| 159 | + headers={"Authorization": "Bearer token"} |
| 160 | + ) |
| 161 | + ) |
| 162 | +``` |
| 163 | + |
| 164 | +### Steps and Processing Order |
| 165 | +```python |
| 166 | +class ComplexInputFilter(InputFilter): |
| 167 | + data: dict = field( |
| 168 | + steps=[ |
| 169 | + {'filters': [ToJsonFilter()]}, |
| 170 | + {'validators': [IsJsonValidator()]}, |
| 171 | + {'filters': [ToDataclassFilter(MyDataclass)]} |
| 172 | + ] |
| 173 | + ) |
| 174 | +``` |
| 175 | + |
| 176 | +## Type Support |
| 177 | + |
| 178 | +- **Full PEP 561 compliance** with `py.typed` marker |
| 179 | +- **Comprehensive type hints** in all modules |
| 180 | +- **Stub files (.pyi)** for enhanced IDE support |
| 181 | +- **Cython extensions** with type declarations |
| 182 | +- **Compatible** with mypy, pyright, and other type checkers |
| 183 | + |
| 184 | +## Performance |
| 185 | + |
| 186 | +- **Cython optimization** available for performance-critical components |
| 187 | +- **Optional compilation** with `pip install flask-inputfilter[compile]` |
| 188 | +- **Fallback to Python** if compilation fails |
| 189 | +- **Benchmarked performance** improvements in validation-heavy scenarios |
| 190 | + |
| 191 | +## Documentation |
| 192 | + |
| 193 | +- **Full Documentation**: https://leandercs.github.io/flask-inputfilter |
| 194 | +- **API Reference**: Complete class and method documentation |
| 195 | +- **Guides**: Step-by-step tutorials and best practices |
| 196 | +- **Examples**: Real-world usage patterns |
| 197 | + |
| 198 | +## Common Patterns |
| 199 | + |
| 200 | +### API Endpoint Validation |
| 201 | +```python |
| 202 | +@app.route('/api/products', methods=['POST']) |
| 203 | +def create_product(): |
| 204 | + class ProductFilter(InputFilter): |
| 205 | + name: str = field(required=True, validators=[LengthValidator(1, 100)]) |
| 206 | + price: float = field(required=True, filters=[ToFloatFilter()], validators=[RangeValidator(0.01, 10000)]) |
| 207 | + category: str = field(validators=[InArrayValidator(['electronics', 'clothing', 'books'])]) |
| 208 | + |
| 209 | + filter_instance = ProductFilter() |
| 210 | + filter_instance.set_data(request.get_json()) |
| 211 | + |
| 212 | + if not filter_instance.is_valid(): |
| 213 | + return jsonify({'errors': filter_instance.get_error_messages()}), 400 |
| 214 | + |
| 215 | + return jsonify(filter_instance.get_values()) |
| 216 | +``` |
| 217 | + |
| 218 | +### Form Data Processing |
| 219 | +```python |
| 220 | +@app.route('/contact', methods=['POST']) |
| 221 | +def contact_form(): |
| 222 | + class ContactFilter(InputFilter): |
| 223 | + email: str = field(required=True, validators=[IsEmailValidator()]) |
| 224 | + message: str = field(required=True, filters=[StringTrimFilter()], validators=[LengthValidator(10, 1000)]) |
| 225 | + subscribe: bool = field(filters=[ToBooleanFilter()]) |
| 226 | + |
| 227 | + # Process form data... |
| 228 | +``` |
| 229 | + |
| 230 | +This guide provides AI agents with the essential context needed to effectively work with Flask InputFilter in any development scenario. |
0 commit comments