صفحهبندی (Pagination) در GraphQL با FastAPI
در پروژههای بزرگ، ممکن است تعداد دادهها بسیار زیاد باشد و بارگذاری تمام آنها در یک Query باعث کندی و مصرف بیش از حد منابع شود. به همین دلیل، صفحهبندی (Pagination) به شما اجازه میدهد که دادهها را به بخشهای کوچکتر تقسیم کرده و فقط قسمت مورد نیاز را ارسال کنید.
روشهای رایج صفحهبندی
- Offset/Limit: سادهترین روش صفحهبندی که در آن شما مشخص میکنید از کدام ردیف شروع شود (
offset
) و حداکثر چند ردیف دریافت شود (limit
). این روش به سرعت قابل پیادهسازی است و برای اکثر موارد کافی است. - Relay Cursor-based Pagination: در این روش به جای شماره صفحه یا offset، از یک
cursor
استفاده میشود که نشاندهنده آخرین آیتم دریافت شده است. این روش مناسب دادههای پویا و تغییرات مداوم است و باعث میشود کارایی و ثبات دادهها بهتر حفظ شود.
پیادهسازی Offset/Limit در FastAPI + GraphQL
فرض کنید میخواهیم تسکهای یک کاربر را به صورت صفحهبندی شده دریافت کنیم. ابتدا Resolver را با پارامترهای skip
و limit
تعریف میکنیم:
# graphql/tasks.py
import strawberry
from graphql.context import get_current_user
from models.tasks import Task as TaskModel
from graphql.types import TaskType
@strawberry.type
class TaskQuery:
@strawberry.field
def tasks_paginated(self, info, skip: int = 0, limit: int = 10) -> list[TaskType]:
db = info.context["db"]
auth_header = info.context["request"].headers.get("authorization")
current_user = get_current_user(auth_header, db)
tasks = db.query(TaskModel)\
.filter(TaskModel.user_id == current_user.id)\
.offset(skip)\
.limit(limit)\
.all()
return [
TaskType(
id=task.id,
title=task.title,
completed=task.completed,
user_id=task.user_id,
created_at=str(task.created_at),
updated_at=str(task.updated_at)
) for task in tasks
]
نحوه استفاده از Query صفحهبندی شده
برای دریافت دادههای صفحه اول با حداکثر 10 آیتم:
{
tasksPaginated(skip: 0, limit: 10) {
id
title
completed
}
}
برای دریافت صفحه دوم، کافی است مقدار skip
را برابر تعداد آیتمهای صفحه اول قرار دهید:
{
tasksPaginated(skip: 10, limit: 10) {
id
title
completed
}
}
مزایای Offset/Limit
- ساده و سریع برای پیادهسازی
- مناسب اکثر پروژههای کوچک تا متوسط
محدودیتها
- اگر دادهها به طور مداوم تغییر کنند (مثلاً حذف یا اضافه شوند)، صفحات بعدی ممکن است دادهها را از دست بدهند یا تکراری شوند.
- برای مجموعههای بزرگ با میلیونها رکورد، offset بالا باعث کاهش کارایی میشود.
نکات پایانی
در مراحل بعد میتوانیم Cursor-based Pagination (مانند استاندارد Relay) را اضافه کنیم تا صفحهبندی در شرایط دادههای پویا و بزرگ بهینهتر شود. برای شروع و اکثر موارد، روش Offset/Limit ساده، قابل فهم و عملی است و میتوان آن را به راحتی با Resolverهای موجود ترکیب کرد.