Generate FastAPI endpoints from a model
In this post, we’ll see how to turn a Pydantic model class into an endpoint where each filed is an endpoint. The reason for why you’d to do this are irrelevant but it is an intersting experiment.
First let’s look at the simplest FastAPI app:
from fastapi import FastAPI
app = FastAPI()
@app.get("/hello")
def hello():
return {"hello": "world"}
When you’ve installed FastAPI, you can run this with just fastapi dev.
A simple curl localhost:8000/hello will show that it works, but if you’re a visual, you can have a look at the docs that are automatically generated: http://localhost:8000/docs.
Here is a screenshot:

Now that you have the basic thing running, we can make things interesting. First, let’s define a somewhat complex model:
class Address(BaseModel):
street: str
city: str
class Person(BaseModel):
name: str
age: int
address: Address
And use it to return from the /person endpoint, the docs are updated nicely:
person_model = Person(name="name", age=18, address=Address(street="street", city="city"))
@app.get("/person")
def person() -> Person:
return person_model

Now let’s use this Person type to generate an endpoint for each field of the class. Well, we’ll do two, one for fetching the value of a field, and the other one for updating it.
To achieve this, we’ll iterate over the model_fields member coming from Pydantic:
for field_name, field_type in Person.model_fields.items():
@app.get(f"/person/{field_name}")
def get_field(field_name: str = field_name): # 1
return person_model.model_dump()[field_name]
@app.put(f"/person/{field_name}")
def put_field( # 2
value: field_type.annotation, # pyright: ignore[reportInvalidTypeForm]
field_name: str = field_name,
):
Person.model_validate( # 3
{
**person_model.model_dump(),
field_name: value,
}
)
return {"message": "Configuration updated successfully"}
The code is nothing fancy, but let’s go over some details that tripped me the first time I implement this:
- because we’re iterating over a loop and creating functions inside the loop, we must be careful when using loop variables inside the functions/lambas we create. I got lucky that I had ruff installed so it told me before I had completed my implementation
- the write side is the more interesting because we want the input type to be properly typed and documented. To do this, we use the
FieldInfo#annotationfunction that returns the type for the given field. The only downside I have found so far is that I can’t getpyrightor any type checker I’ve tried to type check this - we can use Pydantic useful
model_validateto ensure at runtime that the input received is valid within the larger model
Going back to 2, the great thing about it is that it allows FastAPI to correctly annotate everything in the documentation endpoint it builds for you. For example:

And that’s it. If you wanted, you could generate such endpoints under another endpoint through a FastAPI APIRouter instead of the app directly.