FastAPI doesn't allow directly using the HTTP request data in Pydantic models or validators since it violates the separation of concerns principle and couples the models to the specific request context, which should ideally be separated.
However, you can access the HTTP request in the path operation function itself. Here you can extract the Host header, perform your validation, and then pass it to your Item model if needed.
from dataclasses import dataclass
from typing import Union
from fastapi import FastAPI, HTTPException, Depends, Request
from pydantic import BaseModel, validator
class Item(BaseModel):
name: str
price: float
description: Union[str, None] = None
tax: Union[float, None] = None
@validator("name")
def name_must_match_header(cls, v, *, values, **kwargs):
if 'header_value' in values and v != values['header_value']:
raise ValueError('Name must be equal to the host header value')
return v
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item, request: Request):
header_value = request.headers.get('host')
try:
validated_item = Item(**item.dict(), header_value=header_value)
except ValueError as ve:
raise HTTPException(status_code=400, detail=str(ve))
return validated_item
I have slightly refactored the Item model to be a Pydantic BaseModel instead of a dataclass, because FastAPI and Pydantic work better together when using BaseModel. I added a name_must_match_header validator in the Item class which checks if the 'name' field matches the header_value we pass when validating the model. Then, in the path operation function, I extract the 'host' header from the request and validate the Item instance using this header. If the validation fails, it raises an HTTPException with a 400 status code and the validation error as detail. If the validation passes, the function returns the validated item.
Please note that the FastAPI server automatically lowercases all header names so even if you pass Host as the header name, you'll have to retrieve it using host.