Search code examples
python-3.xresponsefastapi

FastAPI how to insert additional Information (like queries) into the Response if you use a Response Model?


I'm trying to build an API right now with FastAPI. I want to have one route (which accepts queries) return them in the response as well so the user can double check what queries he entered (also to see how many pages are there in total etc.).

I'm using the response_model response way and can not for the life of me figure out how to get additional Parameters inserted into the response.

I already tried making all the fields in the response model optional so it no longer throws an error while checking, but it still only (if it responds) responds without the added information. Underneath you can see the route and the schema that I'm using for the response_model.

This is the route I'm wanting to have this applied to.

@router.get("/", response_model=List[schemas.StockResponse], tags=["Stocks"])
def get_stocks(response= Response, db: Session = Depends(get_db), current_user: int = Depends(oauth2.get_current_user), limit: int = 100, skip: int = 0):
    utils.increase_request_counter(current_user, db)
    stocks = db.query(models.Stock).limit(limit).offset(skip).all()
    return stocks

What I would like to have is that it returns the list of stocks but also returns the information about the query parameters above. Like:

[{"params": {
           "limit" : 10,
           "skip": 0 },
 {"data": [ *then list of dictionaries that it already returns*]}]

something like that but I can not get it to return anything but a list of dictionaries.

This is the schema that this model is using (StockResponse)

class StockBase(BaseModel):
    name: str
    ticker: str
    price: float
    dividends: float
    dividend_yield: float
    ftweek_low: Optional[float] = Body(None)
    ftweek_high: Optional[float] = Body(None)
    trading_market: Optional[str] = Body(None)
    market_cap: Optional[int] = Body(None)
    payout_ratio: Optional[float] = Body(None)
    beta: Optional[float] = Body(None)
    business_summary: Optional[str] = Body(None)
    website: Optional[str] = Body(None)
    logo: Optional[str] = Body(None)
    time_updated: Optional[datetime] = Body(datetime.now())
    sector: Optional[str] = Body(None)
    industry: Optional[str] = Body(None)
    
class StockResponse(StockBase):
    ID: Optional[int]
    name: Optional[str]
    ticker: Optional[str]
    price: Optional[float]
    dividends: Optional[float]
    dividend_yield: Optional[float]
    time_created: Optional[datetime]
        
    class Config:
         orm_mode = True    


Solution

  • Create a response model that matches what you want to return, and populate it accordingly:

    from pydantic import BaseModel
    
    
    class StockRequestParams(BaseModel):
      limit: int
      skip: int
    
    
    class StockResponseWithMetadata(BaseModel):
      params: StockRequestParams
      stocks: List[StockResponse]
    
    
    def get_stocks(...):
      ...
      return StockResponseWithMetadata(
        params=StockRequestParams(hits=hits, limit=limit), 
        stocks=socks,
      )