Let's add limit and offset to the query parameters.
By default, we will return the first results from the database, so offset will have a default value of 0.
And by default, we will return a maximum of 100 heroes, so limit will have a default value of 100.
fromfastapiimportFastAPI,HTTPException,QueryfromsqlmodelimportField,Session,SQLModel,create_engine,select# Code here omitted π@app.get("/heroes/",response_model=list[HeroPublic])defread_heroes(offset:int=0,limit:int=Query(default=100,le=100)):withSession(engine)assession:heroes=session.exec(select(Hero).offset(offset).limit(limit)).all()returnheroes# Code below omitted π
fromtypingimportOptionalfromfastapiimportFastAPI,HTTPException,QueryfromsqlmodelimportField,Session,SQLModel,create_engine,select# Code here omitted π@app.get("/heroes/",response_model=list[HeroPublic])defread_heroes(offset:int=0,limit:int=Query(default=100,le=100)):withSession(engine)assession:heroes=session.exec(select(Hero).offset(offset).limit(limit)).all()returnheroes# Code below omitted π
fromtypingimportList,OptionalfromfastapiimportFastAPI,HTTPException,QueryfromsqlmodelimportField,Session,SQLModel,create_engine,select# Code here omitted π@app.get("/heroes/",response_model=List[HeroPublic])defread_heroes(offset:int=0,limit:int=Query(default=100,le=100)):withSession(engine)assession:heroes=session.exec(select(Hero).offset(offset).limit(limit)).all()returnheroes# Code below omitted π
π Full file preview
fromfastapiimportFastAPI,HTTPException,QueryfromsqlmodelimportField,Session,SQLModel,create_engine,selectclassHeroBase(SQLModel):name:str=Field(index=True)secret_name:strage:int|None=Field(default=None,index=True)classHero(HeroBase,table=True):id:int|None=Field(default=None,primary_key=True)classHeroCreate(HeroBase):passclassHeroPublic(HeroBase):id:intsqlite_file_name="database.db"sqlite_url=f"sqlite:///{sqlite_file_name}"connect_args={"check_same_thread":False}engine=create_engine(sqlite_url,echo=True,connect_args=connect_args)defcreate_db_and_tables():SQLModel.metadata.create_all(engine)app=FastAPI()@app.on_event("startup")defon_startup():create_db_and_tables()@app.post("/heroes/",response_model=HeroPublic)defcreate_hero(hero:HeroCreate):withSession(engine)assession:db_hero=Hero.model_validate(hero)session.add(db_hero)session.commit()session.refresh(db_hero)returndb_hero@app.get("/heroes/",response_model=list[HeroPublic])defread_heroes(offset:int=0,limit:int=Query(default=100,le=100)):withSession(engine)assession:heroes=session.exec(select(Hero).offset(offset).limit(limit)).all()returnheroes@app.get("/heroes/{hero_id}",response_model=HeroPublic)defread_hero(hero_id:int):withSession(engine)assession:hero=session.get(Hero,hero_id)ifnothero:raiseHTTPException(status_code=404,detail="Hero not found")returnhero
fromtypingimportOptionalfromfastapiimportFastAPI,HTTPException,QueryfromsqlmodelimportField,Session,SQLModel,create_engine,selectclassHeroBase(SQLModel):name:str=Field(index=True)secret_name:strage:Optional[int]=Field(default=None,index=True)classHero(HeroBase,table=True):id:Optional[int]=Field(default=None,primary_key=True)classHeroCreate(HeroBase):passclassHeroPublic(HeroBase):id:intsqlite_file_name="database.db"sqlite_url=f"sqlite:///{sqlite_file_name}"connect_args={"check_same_thread":False}engine=create_engine(sqlite_url,echo=True,connect_args=connect_args)defcreate_db_and_tables():SQLModel.metadata.create_all(engine)app=FastAPI()@app.on_event("startup")defon_startup():create_db_and_tables()@app.post("/heroes/",response_model=HeroPublic)defcreate_hero(hero:HeroCreate):withSession(engine)assession:db_hero=Hero.model_validate(hero)session.add(db_hero)session.commit()session.refresh(db_hero)returndb_hero@app.get("/heroes/",response_model=list[HeroPublic])defread_heroes(offset:int=0,limit:int=Query(default=100,le=100)):withSession(engine)assession:heroes=session.exec(select(Hero).offset(offset).limit(limit)).all()returnheroes@app.get("/heroes/{hero_id}",response_model=HeroPublic)defread_hero(hero_id:int):withSession(engine)assession:hero=session.get(Hero,hero_id)ifnothero:raiseHTTPException(status_code=404,detail="Hero not found")returnhero
fromtypingimportList,OptionalfromfastapiimportFastAPI,HTTPException,QueryfromsqlmodelimportField,Session,SQLModel,create_engine,selectclassHeroBase(SQLModel):name:str=Field(index=True)secret_name:strage:Optional[int]=Field(default=None,index=True)classHero(HeroBase,table=True):id:Optional[int]=Field(default=None,primary_key=True)classHeroCreate(HeroBase):passclassHeroPublic(HeroBase):id:intsqlite_file_name="database.db"sqlite_url=f"sqlite:///{sqlite_file_name}"connect_args={"check_same_thread":False}engine=create_engine(sqlite_url,echo=True,connect_args=connect_args)defcreate_db_and_tables():SQLModel.metadata.create_all(engine)app=FastAPI()@app.on_event("startup")defon_startup():create_db_and_tables()@app.post("/heroes/",response_model=HeroPublic)defcreate_hero(hero:HeroCreate):withSession(engine)assession:db_hero=Hero.model_validate(hero)session.add(db_hero)session.commit()session.refresh(db_hero)returndb_hero@app.get("/heroes/",response_model=List[HeroPublic])defread_heroes(offset:int=0,limit:int=Query(default=100,le=100)):withSession(engine)assession:heroes=session.exec(select(Hero).offset(offset).limit(limit)).all()returnheroes@app.get("/heroes/{hero_id}",response_model=HeroPublic)defread_hero(hero_id:int):withSession(engine)assession:hero=session.get(Hero,hero_id)ifnothero:raiseHTTPException(status_code=404,detail="Hero not found")returnhero
We want to allow clients to set different offset and limit values.
But we don't want them to be able to set a limit of something like 9999, that's over 9000! π±
So, to prevent it, we add additional validation to the limit query parameter, declaring that it has to be less than or equal to 100 with le=100.
This way, a client can decide to take fewer heroes if they want, but not more.
Info
If you need to refresh how query parameters and their validation work, check out the docs in FastAPI:
You can use FastAPI's automatic data validation to get the parameters for limit and offset, and then use them with the session to control ranges of data to be sent in responses.