Custom Page
Let's create custom page parameter that is compatible with JSON API 1.0 specification.
from typing import Any, Generic, Optional, Sequence, TypeVar
from fastapi import Query
from pydantic import BaseModel
from typing_extensions import Self
from fastapi_pagination.bases import AbstractPage, AbstractParams, RawParams
class JSONAPIParams(BaseModel, AbstractParams):
offset: int = Query(1, ge=1, alias="page[offset]")
limit: int = Query(10, ge=1, le=100, alias="page[limit]")
def to_raw_params(self) -> RawParams:
return RawParams(limit=self.limit, offset=self.offset)
class JSONAPIPageInfoMeta(BaseModel):
total: int
class JSONAPIPageMeta(BaseModel):
page: JSONAPIPageInfoMeta
T = TypeVar("T")
class JSONAPIPage(AbstractPage[T], Generic[T]):
data: Sequence[T]
meta: JSONAPIPageMeta
__params_type__ = JSONAPIParams
@classmethod
def create(
cls,
items: Sequence[T],
params: AbstractParams,
*,
total: Optional[int] = None,
**kwargs: Any,
) -> Self:
assert isinstance(params, JSONAPIParams)
assert total is not None
return cls(
data=items,
meta={"page": {"total": total}},
**kwargs,
)
Step 1: Create pagination params
from typing import Any, Generic, Optional, Sequence, TypeVar
from fastapi import Query
from pydantic import BaseModel
from typing_extensions import Self
from fastapi_pagination.bases import AbstractPage, AbstractParams, RawParams
class JSONAPIParams(BaseModel, AbstractParams):
offset: int = Query(1, ge=1, alias="page[offset]")
limit: int = Query(10, ge=1, le=100, alias="page[limit]")
def to_raw_params(self) -> RawParams:
return RawParams(limit=self.limit, offset=self.offset)
class JSONAPIPageInfoMeta(BaseModel):
total: int
class JSONAPIPageMeta(BaseModel):
page: JSONAPIPageInfoMeta
T = TypeVar("T")
class JSONAPIPage(AbstractPage[T], Generic[T]):
data: Sequence[T]
meta: JSONAPIPageMeta
__params_type__ = JSONAPIParams
@classmethod
def create(
cls,
items: Sequence[T],
params: AbstractParams,
*,
total: Optional[int] = None,
**kwargs: Any,
) -> Self:
assert isinstance(params, JSONAPIParams)
assert total is not None
return cls(
data=items,
meta={"page": {"total": total}},
**kwargs,
)
Step 2: override to_raw_params
method
from typing import Any, Generic, Optional, Sequence, TypeVar
from fastapi import Query
from pydantic import BaseModel
from typing_extensions import Self
from fastapi_pagination.bases import AbstractPage, AbstractParams, RawParams
class JSONAPIParams(BaseModel, AbstractParams):
offset: int = Query(1, ge=1, alias="page[offset]")
limit: int = Query(10, ge=1, le=100, alias="page[limit]")
def to_raw_params(self) -> RawParams:
return RawParams(limit=self.limit, offset=self.offset)
class JSONAPIPageInfoMeta(BaseModel):
total: int
class JSONAPIPageMeta(BaseModel):
page: JSONAPIPageInfoMeta
T = TypeVar("T")
class JSONAPIPage(AbstractPage[T], Generic[T]):
data: Sequence[T]
meta: JSONAPIPageMeta
__params_type__ = JSONAPIParams
@classmethod
def create(
cls,
items: Sequence[T],
params: AbstractParams,
*,
total: Optional[int] = None,
**kwargs: Any,
) -> Self:
assert isinstance(params, JSONAPIParams)
assert total is not None
return cls(
data=items,
meta={"page": {"total": total}},
**kwargs,
)
Step 3: Create custom page
from typing import Any, Generic, Optional, Sequence, TypeVar
from fastapi import Query
from pydantic import BaseModel
from typing_extensions import Self
from fastapi_pagination.bases import AbstractPage, AbstractParams, RawParams
class JSONAPIParams(BaseModel, AbstractParams):
offset: int = Query(1, ge=1, alias="page[offset]")
limit: int = Query(10, ge=1, le=100, alias="page[limit]")
def to_raw_params(self) -> RawParams:
return RawParams(limit=self.limit, offset=self.offset)
class JSONAPIPageInfoMeta(BaseModel):
total: int
class JSONAPIPageMeta(BaseModel):
page: JSONAPIPageInfoMeta
T = TypeVar("T")
class JSONAPIPage(AbstractPage[T], Generic[T]):
data: Sequence[T]
meta: JSONAPIPageMeta
__params_type__ = JSONAPIParams
@classmethod
def create(
cls,
items: Sequence[T],
params: AbstractParams,
*,
total: Optional[int] = None,
**kwargs: Any,
) -> Self:
assert isinstance(params, JSONAPIParams)
assert total is not None
return cls(
data=items,
meta={"page": {"total": total}},
**kwargs,
)
Step 4: override create
page method
from typing import Any, Generic, Optional, Sequence, TypeVar
from fastapi import Query
from pydantic import BaseModel
from typing_extensions import Self
from fastapi_pagination.bases import AbstractPage, AbstractParams, RawParams
class JSONAPIParams(BaseModel, AbstractParams):
offset: int = Query(1, ge=1, alias="page[offset]")
limit: int = Query(10, ge=1, le=100, alias="page[limit]")
def to_raw_params(self) -> RawParams:
return RawParams(limit=self.limit, offset=self.offset)
class JSONAPIPageInfoMeta(BaseModel):
total: int
class JSONAPIPageMeta(BaseModel):
page: JSONAPIPageInfoMeta
T = TypeVar("T")
class JSONAPIPage(AbstractPage[T], Generic[T]):
data: Sequence[T]
meta: JSONAPIPageMeta
__params_type__ = JSONAPIParams
@classmethod
def create(
cls,
items: Sequence[T],
params: AbstractParams,
*,
total: Optional[int] = None,
**kwargs: Any,
) -> Self:
assert isinstance(params, JSONAPIParams)
assert total is not None
return cls(
data=items,
meta={"page": {"total": total}},
**kwargs,
)
Example
Now we can use JSONAPIPage
in our API.