0

I'm trying to implement async validation in FastAPI + Pydantic (v1). I need this to check uniqueness of some unique fields (username, email). I cannot just catch IntegrityError because this won't give field names which I need to return to client so frontend could highlight those fields in form.

P.S. asyncio.sleep imitates database call.

I found to possible solutions but none of them are working:

import asyncio
import concurrent.futures

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr, validator


def synchronize_async_helper(to_await):
    async_response = []

    async def run_and_capture_result():
        r = await to_await
        async_response.append(r)

    loop = asyncio.get_event_loop()
    coroutine = run_and_capture_result()
    loop.run_until_complete(coroutine)

    return async_response[0]


async def validate_username_uniqueness(username):
    #  make database async request 


async def validate_email_uniqueness(email):
    #  make database async request 


class UserCreateSchema(BaseModel):
    username: str  # unique
    email: EmailStr  # unique
    
    first_name: str
    last_name: str
    middle_name: str | None

    @validator("username")
    def validate_username(cls, username: str):
        # method 1
        # does not wait for 10 seconds

        unique = synchronize_async_helper(validate_username_uniqueness())

        if not unique:
            raise

        return username

    @validator("email")
    def validate_email(cls, email):
        # method 2
        # this blocks - one cannot open second browser tab while 10 seconds expire

        pool = concurrent.futures.ThreadPoolExecutor(1)
        unique = pool.submit(asyncio.run, validate_email_uniqueness(email)).result()

        if not unique:
            raise

        return email


app = FastAPI()


@app.post('/users')
async def create_user(user_data: UserCreateSchema):
    ...

How to make async validation possible?

  • _"# this blocks - one cannot open second browser tab while 10 seconds expire"_. Please have a look at [this answer](https://stackoverflow.com/a/71517830/17865804) (particularly, under **Important Note** section). – Chris Aug 11 '23 at 09:34
  • Well the problem remains even if make requests in Postman – Альберт Александров Aug 11 '23 at 12:12
  • The problem is not in browser tabs. Also I cannot await in sync validation method of Pydantic model (validate_email). The problem is how to execute async function (which I cannot change) in sync method (which I also cannot change) in FastAPI application. It's written under the link you gave to use ThreadPoolExecutor does not block but actually blocks. Maybe I'm doing or understanding something wrong? – Альберт Александров Aug 11 '23 at 13:08
  • I updated the question with validation functions (validate_email_uniqueness, validate_username_uniqueness) that should be called inside sync Pydantic validation methods – Альберт Александров Aug 11 '23 at 13:18

0 Answers0