uriyyo / fastapi-pagination

FastAPI pagination 📖
https://uriyyo-fastapi-pagination.netlify.app/
MIT License
1.17k stars 133 forks source link

`Page` with original response structure #1327

Open mattibo opened 1 week ago

mattibo commented 1 week ago

Hi @uriyyo,

I would like to have a pagination style like the GitHub REST API (using link in reponse header) but with the original content as the response (and not the content nested inside e.g. items list with the default Page). Is this possible?

uriyyo commented 1 week ago

Hi @mattibo,

Unfortunately, there is no easy solution like just import stmh like UseHeaderLinks but you can implement you own Page:

from typing import Any, Sequence, TypeVar

from fastapi.applications import FastAPI
from pydantic import RootModel
from typing_extensions import Self

from fastapi_pagination import Page, add_pagination, paginate, response
from fastapi_pagination.bases import AbstractPage, AbstractParams
from fastapi_pagination.links import Page as LinksPage

app = FastAPI()
add_pagination(app)

T = TypeVar("T")

class FlatPage(RootModel[list[T]], AbstractPage[T]):
    __params_type__ = Page.__params_type__

    @classmethod
    def create(
        cls,
        items: Sequence[T],
        params: AbstractParams,
        **kwargs: Any,
    ) -> Self:
        with_links = LinksPage.create(items, params, **kwargs)

        links = []
        for rel, link in (
            ("first", with_links.links.first),
            ("last", with_links.links.last),
            ("next", with_links.links.next),
            ("prev", with_links.links.prev),
        ):
            if link is not None:
                links.append(f'<{link}>; rel="{rel}"')

        if links:
            rsp = response()
            rsp.headers["Link"] = ", ".join(links)

        return cls(with_links.items)

@app.get("/items")
async def read_items() -> FlatPage[int]:
    return paginate(range(1_000))

if __name__ == "__main__":
    import uvicorn

    uvicorn.run(app)