DEV Community

Cover image for Pydantic for FastAPI
Amal Shaji
Amal Shaji Subscriber

Posted on • Edited on • Originally published at blog.amalshaji.com

Pydantic for FastAPI

FastAPI is a modern async framework for Python. According to Python developers survey 2020, FastAPI is the 3rd most popular web framework for python.

What makes FastAPI so popular?

  • Async
  • Fast
  • Easy to Code and fast learning curve.
  • Data validation via Pydantic
  • Automatic docs

Take a look at all the FastAPI features.

Pydantic is a python library for data parsing and validation using Python type hints. It is the fastest python data validation library.

Pydantic for FastAPI

1. BaseSettings for reading environment variables

This requires python-dotenv installed.

 pip install python-dotenv 
Enter fullscreen mode Exit fullscreen mode

Dummy .env file:

 DB_NAME=postgres DB_PASS=postgres DB_URL=postgresql://postgres:postgres@127.0.0.1:5432/postgres DEBUG=True SEED=42 
Enter fullscreen mode Exit fullscreen mode
 # env.py  from pydantic import BaseSettings, PostgresDsn class Settings(BaseSettings): db_name: str db_pass: str db_url: PostgresDsn debug: bool seed: int class Config: env_file = ".env" env_file_encoding = "utf-8" settings = Settings() print(settings) 
Enter fullscreen mode Exit fullscreen mode

Output:

 db_name='postgres' db_pass='postgres' db_url=PostgresDsn('postgresql://postgres:postgres@127.0.0.1:5432/postgres', scheme='postgresql', user='postgres', password='postgres', host='127.0.0.1', host_type='ipv4', port='5432', path='/postgres') debug=True seed=42 
Enter fullscreen mode Exit fullscreen mode
  • The environment variables are automatically loaded by name.
  • They are converted to the types specified by type hints.

By default, all variables are case-insensitive.

You can also use an alias for loading env values. For example, your env variable is DATABASE_URL, but you need to load it as db_url.

 from pydantic import BaseSettings, Field, PostgresDsn class Settings(BaseSettings): db_url: PostgresDsn = Field(..., env="DATABASE_URL") 
Enter fullscreen mode Exit fullscreen mode

Reading the env file is only required if the values are not in the system environment. This process is costly, especially when read for each request. So cache the values using lru_cache.

 from functools import lru_cache # other imports  class Settings(BaseSettings): # All fields, yadayadayada  class Config: env_file = ".env" env_file_encoding = "utf-8" @lru_cache def get_settings() -> Settings: return Settings() settings = get_settings() 
Enter fullscreen mode Exit fullscreen mode

Every time the get_settings is called, the cached values are returned.

2. Validators for custom data validation

Validators are applied to BaseModel to perform custom validation.

Basic BaseModel + FastAPI usage:

 from fastapi import FastAPI from pydantic import BaseModel app = FastAPI() class User(BaseModel): email: str # use EmailStr from pydantic  username: str password: str @app.post("/") async def register(user: User): return user 
Enter fullscreen mode Exit fullscreen mode

Test it out using httpie:

 ➜ http POST 127.0.0.1:8000 email=test@test.com username=amal password=amal HTTP/1.1 200 OK content-length: 61 content-type: application/json date: Wed, 19 May 2021 12:20:06 GMT server: uvicorn { "email": "test@test.com", "password": "amal", "username": "amal" } 
Enter fullscreen mode Exit fullscreen mode

Let's use @validator from pydantic to perform some operation on the BaseModel before the view, register, receives it.

 from pydantic import BaseModel, validator class User(BaseModel): email: str # use EmailStr from pydantic  username: str password: str @validator("password") def hash_the_password(cls, password: str): return f"Fast-Insecure-Hash-{password}" 
Enter fullscreen mode Exit fullscreen mode
 ➜ http POST 127.0.0.1:8000 email=test@test.com username=amal password=amal HTTP/1.1 200 OK content-length: 80 content-type: application/json date: Wed, 19 May 2021 12:39:06 GMT server: uvicorn { "email": "test@test.com", "password": "Fast-Insecure-Hash-amal", "username": "amal" } 
Enter fullscreen mode Exit fullscreen mode

You can also validate a particular field with the rest of the fields.

 @validator("password") def hash_the_password(cls, password, values, **kwargs): print(values.keys()) return password 
Enter fullscreen mode Exit fullscreen mode

This prints dict_keys(['email', 'username']) to stdout. The pydantic fields are validated in sequence, and the values dict carries the already validated fields.

In this case, since we are validating the password field, all the above fields are available to use.

You can use Root Validator to use the entire model's data. By default, the root validator gets data after all the fields are validated(i.e., the default validation).

 @root_validator def test_root_validator(cls, values): print(values.keys()) return values 
Enter fullscreen mode Exit fullscreen mode

Output:

 dict_keys(['email', 'username', 'password']) 
Enter fullscreen mode Exit fullscreen mode

3. schema_extra for providing examples in docs

With the previous example running, if you navigate to http://127.0.0.1:8000/docs, you could see the interactive docs by FastAPI.

Interactive API docs by FastAPI

Instead of string for all values, let's write some custom data for the examples.

 class User(BaseModel): email: str # use EmailStr from pydantic  username: str password: str class Config: schema_extra = { "example": { "email": "test@test.com", "username": "amal", "password": "amal", } } 
Enter fullscreen mode Exit fullscreen mode

Interactive API docs with custom data

You can also use fake data libraries like Faker to generate random data.

Setting the example data can also be achieved like so:

 

class User(BaseModel):
email: str = Field(..., example="test@test.com")
username: str = Field(..., example="amal")
password: str = Field(..., example="amal")

Enter fullscreen mode Exit fullscreen mode




Conclusion

Pydantic is an amazing tool for data validation. FastAPI uses pydantic to help build better APIs. For more amazing features of pydantic, read the official documentation.

Top comments (1)

Collapse
 
sm0ke profile image
Sm0ke

Nice ...