wiwa1978
wiwa1978

Reputation: 2707

FastApi modify response through a response model

I'm using FastAPI to create a simple REST API for my frontends. This REST API backend that I'm developing is in fact a wrapper around another REST API which is pretty complex. The wrapper will also perform additional logic. There is no database involved here.

The code in my backend is defining a route 'projects'. Upon receiving a call, the code is performing a REST call to the vendor's product. Right now, it just passed the response from the vendor's REST API and passes it unaltered on to the frontend.

@app.get("/projects")
async def get_projects():
    projects = RequestsApi(base_url, headers=headers) //RequestsApi is a class responsible for calling a REST API. That REST Api will return a json response
    response = projects.get("/api/projects") 

    return response.json()

The response looks as follows (very much simplified):

{
  "data": [
    {
      "access": "public",
      "customer_id": 1,
      "customer_name": "test1",
      "description": "test1",
      "email": null,
      "id": 11814,
      "name": "test1", 
    },
      "access": "private",
      "customer_id": 3,
      "customer_name": "test2",
      "description": "test2",
      "email": null,
      "id": 11815,
      "name": "test2",   
  ],
  "warnings": []
}

I would want to filter the response to only include the name and description.

So I would like to return to my frontend the following:

{
  "data": [
    {
      "description": "test1",
      "name": "test1", 
    },
      "description": "test2",
      "name": "test2",   
  ]
}

Therefore I created a pydantic model as follows:

class Project(BaseModel):
    name: str
    description: str

And I modified the route by adding the response_model:

@app.get("/projects", response_model=Project)
async def get_projects():
    projects = RequestsApi(base_url, headers=headers)
    response = projects.get("/api/projects")

    return response.json()

Somehow I need to tell that the response maps to the Project model so I can return a project json object just containing the name and description.

How can this be done?

Note: I found a way through constructing it myself but this is surely not the right way to do this:

@app.get("/projects")
async def get_projects():
   projects = RequestsApi(base_url, headers=headers)
   response = projects.get("/api/projects")

   projects = []

   for key in response.json()["data"]:
       myDict = {}
       myDict["name"] = key["name"]
       myDict["description"] = key["description"]
       projects.append(myDict)

   return projects

Upvotes: 1

Views: 3649

Answers (1)

HTF
HTF

Reputation: 7300

You need to specify a list of Pydantic models, like List[Project]:

test.py:

import uvicorn
  
from typing import List

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


DATA = {
    "data": [
        {
            "access": "public",
            "customer_id": 1,
            "customer_name": "test1",
            "description": "test1",
            "email": None,
            "id": 11814,
            "name": "test1",
        },
        {
            "access": "private",
            "customer_id": 3,
            "customer_name": "test2",
            "description": "test2",
            "email": None,
            "id": 11815,
            "name": "test2",
        },
    ],
    "warnings": [],
}


class Project(BaseModel):
    name: str
    description: str


@app.get("/projects", response_model=List[Project])
async def get_projects():
    # projects = RequestsApi(base_url, headers=headers)
    # response = projects.get("/api/projects")
    response = DATA

    return response["data"]


if __name__ == "__main__":
    uvicorn.run("main:app", host="localhost", port=8000, reload=True)

Test:

$ curl -s localhost:8000/projects | python -m json.tool --indent 2
[
  {
    "name": "test1",
    "description": "test1"
  },
  {
    "name": "test2",
    "description": "test2"
  }
]

Upvotes: 1

Related Questions