FastAPI#

new in 0.9.0

Since both FastAPI and Pandera integrates seamlessly with Pydantic, you can use the SchemaModel types to validate incoming or outgoing data with respect to your API endpoints.

Using SchemaModels to Validate Endpoint Inputs and Outputs#

Suppose we want to process transactions, where each transaction has an id and cost. We can model this with a pandera schema model:

# pylint: skip-file
from typing import Optional

from pydantic import BaseModel, Field

import pandera as pa


class Transactions(pa.SchemaModel):
    id: pa.typing.Series[int]
    cost: pa.typing.Series[float] = pa.Field(ge=0, le=1000)

    class Config:
        coerce = True

Also suppose that we expect our endpoint to add a name to the transaction data:

class TransactionsOut(Transactions):
    id: pa.typing.Series[int]
    cost: pa.typing.Series[float]
    name: pa.typing.Series[str]

Let’s also assume that the output of the endpoint should be a list of dictionary records containing the named transactions data. We can do this easily with the to_format option in the schema model BaseConfig.

class TransactionsDictOut(TransactionsOut):
    class Config:
        to_format = "dict"
        to_format_kwargs = {"orient": "records"}

Note that the to_format_kwargs is a dictionary of key-word arguments to be passed into the respective pandas to_{format} method.

Next we’ll create a FastAPI app and define a /transactions/ POST endpoint:

from fastapi import FastAPI, File
from pandera.typing import DataFrame

app = FastAPI()

@app.post("/transactions/", response_model=DataFrame[TransactionsDictOut])
def create_transactions(transactions: DataFrame[Transactions]):
    output = transactions.assign(name="foo")
    ...  # do other stuff, e.g. update backend database with transactions
    return output

Reading File Uploads#

Similar to the TransactionsDictOut example to convert dataframes to a particular format as an endpoint response, pandera also provides a from_format schema model configuration option to read a dataframe from a particular serialization format.

class TransactionsParquet(Transactions):
    class Config:
        from_format = "parquet"

Let’s also define a response model for the /file/ upload endpoint:

class TransactionsJsonOut(TransactionsOut):
    class Config:
        to_format = "json"
        to_format_kwargs = {"orient": "records"}

class ResponseModel(BaseModel):
    filename: str
    df: pa.typing.DataFrame[TransactionsJsonOut]

In the next example, we use the pandera UploadFile type to upload a parquet file to the /file/ POST endpoint and return a response containing the filename and the modified data in json format.

from pandera.typing.fastapi import UploadFile

@app.post("/file/", response_model=ResponseModel)
def create_upload_file(
    file: UploadFile[DataFrame[TransactionsParquet]] = File(...),
):
    return {
        "filename": file.filename,
        "df": file.data.assign(name="foo"),
    }

Pandera’s UploadFile type is a subclass of FastAPI’s UploadFile but it exposes a .data property containing the pandera-validated dataframe.

Takeaway#

With the FastAPI and Pandera integration, you can use Pandera SchemaModel types to validate the dataframe inputs and outputs of your FastAPI endpoints.