Stable release of aiogram-forms is out

The stable version of aiogram-forms is finally out! Well, to be honest, version 1.0.0 was released on December 30, but the note is only coming out now, because in January I was doing blog updates and other projects.

First of all, the release is aimed at supporting the 3rd version of aiogram, which BTW turned out to be quite pleasant in terms of API. Also, core was rewritten from scratch, covered with tests and type annotations for 100% in order to avoid possible bugs as much as possible.

Let's look at aiogram-forms usage by writing user registration bot. First of all, you need to describe your form: email with a hint, a phone number with the ability to share contact in one click and a password:

from aiogram_forms.forms import Form, fields, FormsManager

class RegisterForm(Form):
    email = fields.EmailField('Email', help_text='We will send confirmation code.')
    phone = fields.PhoneNumberField('Phone number', share_contact=True)
    password = fields.TextField('Password')

In addition to generic fields and their validators, we can use the validators parameter to define our own rules for the field, and even override error messages via error_messages:

from aiogram_forms.errors import ValidationError

def validate_password_format(value: str):
    special_characters = "!@#$%^&*()-+?_=,<>/"
    if not any(character in special_characters for character in value):
        raise ValidationError('Password should contain special character!', code='weak_password')

class RegisterForm(Form):
    password = fields.TextField(
            'min_length': 'Password should contain at least 8 characters!'

Next, register the form with a unique identifier, which can then be used to interact with the form:

from aiogram_forms import dispatcher

class RegisterForm(Form):

To handle our form submission after all fields have been processed, we can add a callback method to our form. For example, to say thank you after validating the last form field:

class RegisterForm(Form):

    async def callback(cls, message: types.Message, **data) -> None:
        await message.answer(text='Thanks! We will contact you for details.')

At this stage, we have everything to allow users to process our form. In order to start form processing, we use the FormsManager manager available automatically via the aiogram dependency injector:

from aiogram_forms.forms import FormsManager

async def command_start(message: Message, forms: FormsManager) -> None:
    await forms.show('register')

In the same way, we can use the manager's get_data method to get form fields as dictionary:

class RegisterForm(Form):
    email = fields.EmailField('Email', help_text='We will send confirmation code.')

    async def callback(cls, message: types.Message, forms: FormsManager, **data) -> None:
        data = await forms.get_data(RegisterForm)
        await my_service.send_confirmation(data['email'])
        await message.answer(text=f'Thanks! We have send an email with confirmation code.')

The hastily compiled documentation is available here (will be updated). Questions and problems can be left in issues. If the project turned out to be interesting or useful, please give it a star on GitHub ⭐️