Declarative API

Overview

The Declarative API is the modern, recommended way to define InputFilters in flask-inputfilter. It uses Python decorators and class-level declarations to create clean, readable, and maintainable input validation definitions.

Key Features

  • Clean Syntax: Define fields, conditions, and global components directly in class definition

  • Type Safety: Integrates well with type hints and IDEs

  • Inheritance Support: Full support for class inheritance and MRO

  • Model Integration: Automatic serialization to dataclasses, Pydantic models, and more

  • Multiple Element Support: Register multiple components at once for concise definitions

Core Components

The Declarative API consists of four main decorators:

Quick Example

   from flask_inputfilter import InputFilter
   from flask_inputfilter.declarative import field, condition, global_filter, global_validator, model
   from flask_inputfilter.filters import StringTrimFilter, ToLowerFilter
   from flask_inputfilter.validators import IsStringValidator, LengthValidator, EmailValidator
   from flask_inputfilter.conditions import EqualCondition
   from dataclasses import dataclass

   @dataclass
   class User:
       username: str
       email: str
       password: str

   class UserRegistrationFilter(InputFilter):
       # Field definitions with individual configuration
       username = field(
           required=True,
           validators=[LengthValidator(min_length=3, max_length=20)]
       )

       email = field(
           required=True,
           validators=[EmailValidator()]
       )

       password = field(required=True, validators=[LengthValidator(min_length=8)])
       password_confirmation = field(required=True)

       # Global components - applied to all fields
       global_filter(StringTrimFilter(), ToLowerFilter())
       global_validator(IsStringValidator())

       # Cross-field validation
       condition(EqualCondition('password', 'password_confirmation'))

       # Model association
       model(User)

Declarative API

class MyFilter(InputFilter):
    name = field(required=True, validators=[IsStringValidator()])
    email = field(required=True, validators=[EmailValidator()])

    global_filter(StringTrimFilter())
    condition(RequiredCondition('name'))

Inheritance and MRO

The Declarative API fully supports Python’s inheritance and Method Resolution Order (MRO):

class BaseUserFilter(InputFilter):
    # Base fields
    name = field(required=True, validators=[IsStringValidator()])

    # Base global components
    global_filter(StringTrimFilter())

class ExtendedUserFilter(BaseUserFilter):
    # Additional fields
    email = field(required=True, validators=[EmailValidator()])
    age = field(required=False, validators=[IsIntegerValidator()])

    # Additional global components (inherited ones are preserved)
    global_validator(LengthValidator(min_length=1))

    # Conditions
    condition(RequiredCondition('email'))

Field Override

You can override fields from parent classes:

class BaseFilter(InputFilter):
    name = field(required=False)  # Optional in base

class StrictFilter(BaseFilter):
    name = field(required=True, validators=[LengthValidator(min_length=2)])  # Override

Multiple Element Registration

You can register multiple components at once for cleaner definitions:

class CompactFilter(InputFilter):
    name = field(required=True)
    email = field(required=True)

    # Multiple global filters
    global_filter(StringTrimFilter(), ToLowerFilter(), RemoveExtraSpacesFilter())

    # Multiple global validators
    global_validator(IsStringValidator(), NotEmptyValidator())

    # Multiple conditions
    condition(
        RequiredCondition('name'),
        RequiredCondition('email'),
        EqualCondition('password', 'password_confirmation')
    )

Model Integration

The Declarative API seamlessly integrates with various model types:

Dataclasses

from dataclasses import dataclass

@dataclass
class User:
    name: str
    email: str

class UserFilter(InputFilter):
    name = field(required=True, validators=[IsStringValidator()])
    email = field(required=True, validators=[EmailValidator()])

    model(User)

# Usage
filter_instance = UserFilter()
user = filter_instance.validate_data({'name': 'John', 'email': 'john@example.com'})
# user is a User dataclass instance

Pydantic Models

from pydantic import BaseModel

class User(BaseModel):
    name: str
    email: str

class UserFilter(InputFilter):
    name = field(required=True, validators=[IsStringValidator()])
    email = field(required=True, validators=[EmailValidator()])

    model(User)

TypedDict

from typing import TypedDict

class UserDict(TypedDict):
    name: str
    email: str

class UserFilter(InputFilter):
    name = field(required=True, validators=[IsStringValidator()])
    email = field(required=True, validators=[EmailValidator()])

    model(UserDict)

Next Steps

For detailed information about each component, see: