عند بناء واجهات برمجة تطبيقات REST (REST APIs) التي تُرجع قائمة بالموارد، من الضروري النظر في كيفية التعامل مع مجموعات البيانات الكبيرة. إن إرجاع آلاف أو حتى ملايين السجلات في استجابة واحدة لواجهة برمجة التطبيقات أمر غير عملي ويمكن أن يؤدي إلى مشاكل كبيرة في الأداء، واستهلاك عالٍ للذاكرة لكل من الخادم والعميل، وتجربة مستخدم سيئة. الترقيم (Pagination) هو الحل القياسي لهذه المشكلة. يتضمن تقسيم مجموعة بيانات كبيرة إلى أجزاء أصغر قابلة للإدارة تسمى "صفحات"، والتي يتم تقديمها بعد ذلك بالتتابع. سيرشدك هذا البرنامج التعليمي خلال الخطوات التقنية لتنفيذ استراتيجيات ترقيم متنوعة في واجهات برمجة تطبيقات REST الخاصة بك.
هل تريد منصة متكاملة وشاملة لفريق المطورين الخاص بك للعمل معًا بأقصى إنتاجية؟
يلبي Apidog جميع متطلباتك، ويحل محل Postman بسعر معقول جدًا!
لماذا الترقيم ضروري؟
قبل الخوض في تفاصيل التنفيذ، دعونا نتطرق بإيجاز إلى سبب كون الترقيم ميزة غير قابلة للتفاوض لواجهات برمجة التطبيقات التي تتعامل مع مجموعات الموارد:
- الأداء: قد يكون طلب ونقل كميات كبيرة من البيانات بطيئًا. يقلل الترقيم من حجم حمولة كل طلب، مما يؤدي إلى أوقات استجابة أسرع وتقليل حمل الخادم.
- استهلاك الموارد: الاستجابات الأصغر تستهلك ذاكرة أقل على الخادم الذي يولدها وعلى العميل الذي يحللها. هذا أمر بالغ الأهمية بشكل خاص للعملاء المتنقلين أو البيئات ذات الموارد المحدودة.
- تحديد المعدل والحصص: تفرض العديد من واجهات برمجة التطبيقات تحديدًا للمعدل. يساعد الترقيم العملاء على البقاء ضمن هذه الحدود عن طريق جلب البيانات في أجزاء أصغر بمرور الوقت، بدلاً من محاولة الحصول على كل شيء دفعة واحدة.
- تجربة المستخدم: بالنسبة لواجهات المستخدم التي تستهلك واجهة برمجة التطبيقات، فإن تقديم البيانات في صفحات يكون أكثر سهولة في الاستخدام من إغراق المستخدمين بقائمة ضخمة أو تمرير طويل جدًا.
- كفاءة قاعدة البيانات: جلب مجموعة فرعية من البيانات يكون عمومًا أقل إرهاقًا لقاعدة البيانات مقارنة باسترداد جدول كامل، خاصة إذا كان الفهرسة المناسبة موجودة.
استراتيجيات الترقيم الشائعة
هناك العديد من الاستراتيجيات الشائعة لتنفيذ الترقيم، ولكل منها مجموعة من المقايضات الخاصة بها. سنستكشف الأكثر شيوعًا: الترقيم القائم على الإزاحة/الحد (offset/limit) (الذي يشار إليه غالبًا بالترقيم المستند إلى الصفحة) والترقيم المستند إلى المؤشر (cursor-based) (المعروف أيضًا بترقيم المفاتيح أو البحث).
1. الترقيم القائم على الإزاحة/الحد (Offset/Limit) أو المستند إلى الصفحة
هذه هي بلا شك الطريقة الأكثر وضوحًا والأكثر اعتمادًا على نطاق واسع للترقيم. تعمل عن طريق السماح للعميل بتحديد معلمتين رئيسيتين:
offset
: عدد السجلات التي يجب تخطيها من بداية مجموعة البيانات.limit
: الحد الأقصى لعدد السجلات التي سيتم إرجاعها في صفحة واحدة.
بدلاً من ذلك، قد يحدد العملاء:
page
: رقم الصفحة التي يريدون استردادها.pageSize
(أوper_page
،limit
): عدد السجلات في كل صفحة.
يمكن حساب offset
من page
و pageSize
باستخدام الصيغة: offset = (page - 1) * pageSize
.
خطوات التنفيذ التقني:
لنفترض أن لدينا نقطة نهاية API /items
تُرجع قائمة بالعناصر.
أ. معلمات طلب API:
سيقوم العميل بتقديم طلب مثل:GET /items?offset=20&limit=10
(جلب 10 عناصر، تخطي أول 20)
أوGET /items?page=3&pageSize=10
(جلب الصفحة الثالثة، مع 10 عناصر في كل صفحة، وهو ما يعادل offset=20, limit=10).
من الممارسات الجيدة تعيين قيم افتراضية لهذه المعلمات (مثل limit=20
، offset=0
أو page=1
، pageSize=20
) إذا لم يقدمها العميل. أيضًا، فرض حد أقصى لـ limit
أو pageSize
لمنع العملاء من طلب عدد كبير جدًا من السجلات، مما قد يجهد الخادم.
ب. منطق الواجهة الخلفية (مفاهيمي):
عندما يتلقى الخادم هذا الطلب، يحتاج إلى ترجمة هذه المعلمات إلى استعلام قاعدة بيانات.
// Example in Java with Spring Boot
@GetMapping("/items")
public ResponseEntity<PaginatedResponse<Item>> getItems(
@RequestParam(defaultValue = "0") int offset,
@RequestParam(defaultValue = "20") int limit
) {
// Validate limit to prevent abuse
if (limit > 100) {
limit = 100; // Enforce a max limit
}
List<Item> items = itemRepository.findItemsWithOffsetLimit(offset, limit);
long totalItems = itemRepository.countTotalItems(); // For metadata
// Construct and return paginated response
// ...
}
ج. استعلام قاعدة البيانات (مثال SQL):
تدعم معظم قواعد البيانات العلائقية عبارات offset و limit مباشرة.
لـ PostgreSQL أو MySQL:
SELECT *
FROM items
ORDER BY created_at DESC -- Consistent ordering is crucial for stable pagination
LIMIT 10 -- This is the 'limit' parameter
OFFSET 20; -- This is the 'offset' parameter
لـ SQL Server (قد تستخدم الإصدارات الأقدم ROW_NUMBER()
):
SELECT *
FROM items
ORDER BY created_at DESC
OFFSET 20 ROWS
FETCH NEXT 10 ROWS ONLY;
لـ Oracle:
SELECT *
FROM (
SELECT i.*, ROWNUM rnum
FROM (
SELECT *
FROM items
ORDER BY created_at DESC
) i
WHERE ROWNUM <= 20 + 10 -- offset + limit
)
WHERE rnum > 20; -- offset
ملاحظة هامة حول الترتيب: لكي يكون الترقيم القائم على الإزاحة/الحد موثوقًا به، يجب أن يتم فرز مجموعة البيانات الأساسية بواسطة مفتاح متناسق وفريد (أو شبه فريد)، أو مجموعة من المفاتيح. إذا كان ترتيب العناصر يمكن أن يتغير بين الطلبات (على سبيل المثال، يتم إدراج عناصر جديدة أو تحديث عناصر بطريقة تؤثر على ترتيب فرزها)، فقد يرى المستخدمون عناصر مكررة أو يفقدون عناصر عند التنقل بين الصفحات. الخيار الشائع هو الفرز حسب الطابع الزمني للإنشاء أو المعرف الأساسي.
د. هيكل استجابة API:
يجب أن تتضمن استجابة الترقيم الجيدة ليس فقط البيانات للصفحة الحالية ولكن أيضًا بيانات وصفية لمساعدة العميل على التنقل.
{
"data": [
// array of items for the current page
{ "id": "item_21", "name": "Item 21", ... },
{ "id": "item_22", "name": "Item 22", ... },
// ... up to 'limit' items
{ "id": "item_30", "name": "Item 30", ... }
],
"pagination": {
"offset": 20,
"limit": 10,
"totalItems": 5000, // Total number of items available
"totalPages": 500, // Calculated as ceil(totalItems / limit)
"currentPage": 3 // Calculated as (offset / limit) + 1
},
"links": { // HATEOAS links for navigation
"self": "/items?offset=20&limit=10",
"first": "/items?offset=0&limit=10",
"prev": "/items?offset=10&limit=10", // Null if on the first page
"next": "/items?offset=30&limit=10", // Null if on the last page
"last": "/items?offset=4990&limit=10"
}
}
توفير روابط HATEOAS (Hypermedia as the Engine of Application State) (self
, first
, prev
, next
, last
) هو أفضل ممارسة لـ REST. يسمح للعملاء بالتنقل عبر الصفحات دون الحاجة إلى بناء عناوين URL بأنفسهم.
إيجابيات الترقيم القائم على الإزاحة/الحد:
- البساطة: سهل الفهم والتنفيذ.
- التنقل الحالاتي: يسمح بالتنقل المباشر إلى أي صفحة محددة (مثل "الانتقال إلى الصفحة 50").
- مدعوم على نطاق واسع: دعم قاعدة البيانات لـ
OFFSET
وLIMIT
شائع.
سلبيات الترقيم القائم على الإزاحة/الحد:
- تدهور الأداء مع الإزاحات الكبيرة: مع زيادة قيمة
offset
، قد تصبح قواعد البيانات أبطأ. غالبًا ما لا تزال قاعدة البيانات مضطرة إلى مسح جميع صفوفoffset + limit
قبل تجاهل صفوفoffset
. قد يكون هذا غير فعال للصفحات العميقة. - انحراف البيانات/العناصر المفقودة: إذا تمت إضافة عناصر جديدة أو إزالة عناصر موجودة من مجموعة البيانات أثناء ترقيم المستخدم، يمكن أن تتحرك "نافذة" البيانات. قد يتسبب هذا في رؤية المستخدم لنفس العنصر في صفحتين مختلفتين أو فقدان عنصر بالكامل. هذا مشكل بشكل خاص مع مجموعات البيانات التي يتم تحديثها بشكل متكرر. على سبيل المثال، إذا كنت في الصفحة 2 (العناصر 11-20) وتمت إضافة عنصر جديد في بداية القائمة، فعند طلب الصفحة 3، ما كان سابقًا العنصر 21 هو الآن العنصر 22. قد تفقد العنصر الجديد 21 أو ترى عناصر مكررة اعتمادًا على التوقيت الدقيق وأنماط الحذف.
2. الترقيم المستند إلى المؤشر (Keyset/Seek)
يعالج الترقيم المستند إلى المؤشر بعض أوجه القصور في الترقيم القائم على الإزاحة/الحد، لا سيما الأداء مع مجموعات البيانات الكبيرة ومشكلات اتساق البيانات. بدلاً من الاعتماد على إزاحة مطلقة، فإنه يستخدم "مؤشرًا" يشير إلى عنصر معين في مجموعة البيانات. يطلب العميل بعد ذلك العناصر "بعد" أو "قبل" هذا المؤشر.
عادةً ما يكون المؤشر سلسلة مبهمة تقوم بترميز قيمة (قيم) مفتاح (مفاتيح) الفرز للعنصر الأخير الذي تم استرداده في الصفحة السابقة.
خطوات التنفيذ التقني:
أ. معلمات طلب API:
سيقوم العميل بتقديم طلب مثل:GET /items?limit=10
(للصفحة الأولى)
وللصفحات اللاحقة:GET /items?limit=10&after_cursor=opaquestringrepresentinglastitemid
أو، للترقيم للخلف (أقل شيوعًا ولكنه ممكن):GET /items?limit=10&before_cursor=opaquestringrepresentingfirstitemid
لا تزال معلمة limit
تحدد حجم الصفحة.
ب. ما هو المؤشر؟
يجب أن يكون المؤشر:
- مبهمًا للعميل: لا يجب أن يحتاج العميل إلى فهم هيكله الداخلي. يتلقاه فقط من استجابة واحدة ويرسله مرة أخرى في الطلب التالي.
- يعتمد على عمود (أعمدة) فريدة ومرتبة تسلسليًا: عادةً ما يكون هذا هو المعرف الأساسي (إذا كان تسلسليًا مثل UUIDv1 أو تسلسل قاعدة بيانات) أو عمود طابع زمني. إذا لم يكن عمود واحد فريدًا بدرجة كافية (على سبيل المثال، يمكن أن يكون للعديد من العناصر نفس الطابع الزمني)، يتم استخدام مجموعة من الأعمدة (على سبيل المثال،
timestamp
+id
). - قابل للترميز وفك الترميز: غالبًا ما يتم ترميزه بـ Base64 لضمان سلامته في عناوين URL. يمكن أن يكون بسيطًا مثل المعرف نفسه، أو كائن JSON
{ "last_id": 123, "last_timestamp": "2023-10-27T10:00:00Z" }
والذي يتم بعد ذلك ترميزه بـ Base64.
ج. منطق الواجهة الخلفية (مفاهيمي):
// Example in Java with Spring Boot
@GetMapping("/items")
public ResponseEntity<CursorPaginatedResponse<Item>> getItems(
@RequestParam(defaultValue = "20") int limit,
@RequestParam(required = false) String afterCursor
) {
// Validate limit
if (limit > 100) {
limit = 100;
}
// Decode cursor to get the last seen item's properties
// e.g., LastSeenItemDetails lastSeen = decodeCursor(afterCursor);
// If afterCursor is null, it's the first page.
List<Item> items;
if (afterCursor != null) {
DecodedCursor decoded = decodeCursor(afterCursor); // e.g., { lastId: "some_uuid", lastCreatedAt: "timestamp" }
items = itemRepository.findItemsAfter(decoded.getLastCreatedAt(), decoded.getLastId(), limit);
} else {
items = itemRepository.findFirstPage(limit);
}
String nextCursor = null;
if (!items.isEmpty() && items.size() == limit) {
// Assuming items are sorted, the last item in the list is used to generate the next cursor
Item lastItemOnPage = items.get(items.size() - 1);
nextCursor = encodeCursor(lastItemOnPage.getCreatedAt(), lastItemOnPage.getId());
}
// Construct and return cursor paginated response
// ...
}
// Helper methods for encoding/decoding cursors
// private DecodedCursor decodeCursor(String cursor) { ... }
// private String encodeCursor(Timestamp createdAt, String id) { ... }
د. استعلام قاعدة البيانات (مثال SQL):
المفتاح هو استخدام عبارة WHERE
التي تقوم بتصفية السجلات بناءً على مفتاح (مفاتيح) الفرز من المؤشر. يجب أن تتوافق عبارة ORDER BY
مع تكوين المؤشر.
بافتراض الفرز حسب created_at
(تنازلي) ثم حسب id
(تنازلي) كفاصل تعادل لترتيب مستقر إذا لم يكن created_at
فريدًا:
للصفحة الأولى:
SELECT *
FROM items
ORDER BY created_at DESC, id DESC
LIMIT 10;
للصفحات اللاحقة، إذا تم فك ترميز المؤشر إلى last_created_at_from_cursor
و last_id_from_cursor
:
SELECT *
FROM items
WHERE (created_at, id) < (CAST('last_created_at_from_cursor' AS TIMESTAMP), CAST('last_id_from_cursor' AS UUID)) -- Or appropriate types
-- For ascending order, it would be >
-- The tuple comparison (created_at, id) < (val1, val2) is a concise way to write:
-- WHERE created_at < 'last_created_at_from_cursor'
-- OR (created_at = 'last_created_at_from_cursor' AND id < 'last_id_from_cursor')
ORDER BY created_at DESC, id DESC
LIMIT 10;
هذا النوع من الاستعلامات فعال للغاية، خاصة إذا كان هناك فهرس على (created_at, id)
. يمكن لقاعدة البيانات أن "تبحث" مباشرة عن نقطة البداية دون مسح الصفوف غير ذات الصلة.
هـ. هيكل استجابة API:
{
"data": [
// array of items for the current page
{ "id": "item_N", "createdAt": "2023-10-27T10:05:00Z", ... },
// ... up to 'limit' items
{ "id": "item_M", "createdAt": "2023-10-27T10:00:00Z", ... }
],
"pagination": {
"limit": 10,
"hasNextPage": true, // boolean indicating if there's more data
"nextCursor": "base64encodedcursorstringforitem_M" // opaque string
// Potentially a "prevCursor" if bi-directional cursors are supported
},
"links": {
"self": "/items?limit=10&after_cursor=current_request_cursor_if_any",
"next": "/items?limit=10&after_cursor=base64encodedcursorstringforitem_M" // Null if no next page
}
}
لاحظ أن الترقيم المستند إلى المؤشر لا يوفر عادةً totalPages
أو totalItems
لأن حساب هذه يتطلب مسحًا كاملاً للجدول، مما يلغي بعض فوائد الأداء. إذا كانت هذه مطلوبة بشدة، يمكن توفير نقطة نهاية منفصلة أو تقدير.
إيجابيات الترقيم المستند إلى المؤشر:
- الأداء على مجموعات البيانات الكبيرة: يؤدي بشكل عام أداء أفضل من الترقيم القائم على الإزاحة/الحد للترقيم العميق، حيث يمكن لقاعدة البيانات البحث بكفاءة عن موضع المؤشر باستخدام الفهارس.
- مستقر في مجموعات البيانات الديناميكية: أقل عرضة للعناصر المفقودة أو المكررة عند إضافة أو إزالة البيانات بشكل متكرر، حيث يثبت المؤشر على عنصر معين. إذا تم حذف عنصر قبل المؤشر، فلن يؤثر ذلك على العناصر اللاحقة.
- مناسب للتمرير اللانهائي: نموذج "الصفحة التالية" يتناسب بشكل طبيعي مع واجهات المستخدم ذات التمرير اللانهائي.
سلبيات الترقيم المستند إلى المؤشر:
- لا يوجد "الانتقال إلى الصفحة": لا يمكن للمستخدمين التنقل مباشرة إلى رقم صفحة عشوائي (مثل "الصفحة 5"). التنقل تسلسلي بحت (التالي/السابق).
- تنفيذ أكثر تعقيدًا: قد يكون تعريف وإدارة المؤشرات، خاصة مع أعمدة فرز متعددة أو ترتيب فرز معقد، أكثر تعقيدًا.
- قيود الفرز: يجب أن يكون ترتيب الفرز ثابتًا ويعتمد على الأعمدة المستخدمة للمؤشر. تغيير ترتيب الفرز أثناء التنقل باستخدام المؤشرات أمر معقد.
اختيار الاستراتيجية الصحيحة
يعتمد الاختيار بين الترقيم القائم على الإزاحة/الحد والترقيم المستند إلى المؤشر على متطلباتك المحددة:
- الإزاحة/الحد غالبًا ما يكون كافيًا إذا:
- مجموعة البيانات صغيرة نسبيًا أو لا تتغير بشكل متكرر.
- القدرة على الانتقال إلى صفحات عشوائية ميزة حاسمة.
- بساطة التنفيذ أولوية قصوى.
- الأداء للصفحات العميقة جدًا ليس مصدر قلق كبير.
- المستند إلى المؤشر مفضل بشكل عام إذا:
- تتعامل مع مجموعات بيانات كبيرة جدًا وتتغير بشكل متكرر.
- الأداء على نطاق واسع واتساق البيانات أثناء الترقيم أمران أساسيان.
- التنقل التسلسلي (مثل التمرير اللانهائي) هو حالة الاستخدام الأساسية.
- لا تحتاج إلى عرض إجمالي عدد الصفحات أو السماح بالانتقال إلى صفحات محددة.
في بعض الأنظمة، يتم استخدام نهج هجين، أو يتم تقديم استراتيجيات مختلفة لحالات استخدام أو نقاط نهاية مختلفة.
أفضل الممارسات لتنفيذ الترقيم
بغض النظر عن الاستراتيجية المختارة، التزم بأفضل الممارسات التالية:
- تسمية المعلمات المتسقة: استخدم أسماء واضحة ومتسقة لمعلمات الترقيم الخاصة بك (مثل
limit
،offset
،page
،pageSize
،after_cursor
،before_cursor
). التزم بتقليد واحد (مثلcamelCase
أوsnake_case
) في جميع أنحاء واجهة برمجة التطبيقات الخاصة بك. - توفير روابط التنقل (HATEOAS): كما هو موضح في أمثلة الاستجابة، قم بتضمين روابط لـ
self
،next
،prev
،first
، وlast
(حيثما ينطبق ذلك). هذا يجعل واجهة برمجة التطبيقات أكثر قابلية للاكتشاف ويفصل العميل عن منطق بناء عناوين URL. - القيم الافتراضية والحدود القصوى:
- قم دائمًا بتعيين قيم افتراضية معقولة لـ
limit
(مثل 10 أو 25). - فرض حد أقصى لـ
limit
لمنع العملاء من طلب الكثير من البيانات وإرهاق الخادم (مثل 100 سجل كحد أقصى لكل صفحة). أعد خطأ أو حدد الحد إذا تم طلب قيمة غير صالحة.
- توثيق واضح لواجهة برمجة التطبيقات: قم بتوثيق استراتيجية الترقيم الخاصة بك بشكل شامل:
- شرح المعلمات المستخدمة.
- تقديم أمثلة للطلبات والاستجابات.
- توضيح الحدود الافتراضية والقصوى.
- شرح كيفية استخدام المؤشرات (إذا كانت قابلة للتطبيق)، دون الكشف عن هيكلها الداخلي إذا كان من المفترض أن تكون مبهمة.
- الفرز المتسق: تأكد من أن البيانات الأساسية مرتبة بشكل متسق لكل طلب ترقيم. بالنسبة للإزاحة/الحد، هذا أمر حيوي لتجنب انحراف البيانات. بالنسبة للترقيم المستند إلى المؤشر، يحدد ترتيب الفرز كيفية بناء وتفسير المؤشرات. استخدم عمود فاصل تعادل فريد (مثل المعرف الأساسي) إذا كان عمود الفرز الأساسي يمكن أن يحتوي على قيم مكررة.
- التعامل مع الحالات الهامشية:
- النتائج الفارغة: أعد مصفوفة بيانات فارغة وبيانات وصفية ترقيم مناسبة (مثل
totalItems: 0
أوhasNextPage: false
). - المعلمات غير الصالحة: أعد خطأ
400 Bad Request
إذا قدم العملاء معلمات ترقيم غير صالحة (مثل حد سالب، رقم صفحة غير صحيح). - المؤشر غير موجود (للمستند إلى المؤشر): إذا كان المؤشر المقدم غير صالح أو يشير إلى عنصر محذوف، قرر سلوكًا: أعد
404 Not Found
أو400 Bad Request
، أو ارجع برشاقة إلى الصفحة الأولى.
- اعتبارات العدد الإجمالي:
- بالنسبة للإزاحة/الحد، يعد توفير
totalItems
وtotalPages
أمرًا شائعًا. كن على دراية بأنCOUNT(*)
يمكن أن يكون بطيئًا على الجداول الكبيرة جدًا. استكشف تحسينات أو تقديرات خاصة بقاعدة البيانات إذا أصبح هذا عنق زجاجة. - بالنسبة للترقيم المستند إلى المؤشر، غالبًا ما يتم حذف
totalItems
لتحسين الأداء. إذا كان ضروريًا، ففكر في توفير عدد تقديري أو نقطة نهاية منفصلة تحسبه (ربما بشكل غير متزامن).
- معالجة الأخطاء: أعد رموز حالة HTTP المناسبة للأخطاء (مثل
400
للإدخال السيئ،500
لأخطاء الخادم أثناء جلب البيانات). - الأمان: على الرغم من أنها ليست آلية ترقيم مباشرة، تأكد من أن البيانات التي يتم ترقيمها تحترم قواعد التفويض. يجب أن يكون المستخدم قادرًا فقط على الترقيم عبر البيانات التي يُسمح له برؤيتها.
- التخزين المؤقت: يمكن غالبًا تخزين استجابات الترقيم مؤقتًا. بالنسبة للترقيم المستند إلى الإزاحة،
GET /items?page=2&pageSize=10
قابل للتخزين المؤقت بشكل كبير. بالنسبة للترقيم المستند إلى المؤشر،GET /items?limit=10&after_cursor=XYZ
قابل للتخزين المؤقت أيضًا. تأكد من أن استراتيجية التخزين المؤقت الخاصة بك تعمل بشكل جيد مع كيفية إنشاء واستهلاك روابط الترقيم. يجب النظر في استراتيجيات الإلغاء إذا تغيرت البيانات الأساسية بشكل متكرر.
مواضيع متقدمة (إشارات موجزة)
- التمرير اللانهائي: الترقيم المستند إلى المؤشر يتناسب بشكل طبيعي مع واجهات المستخدم ذات التمرير اللانهائي. يجلب العميل الصفحة الأولى، وعندما يمرر المستخدم بالقرب من الأسفل، يستخدم
nextCursor
لجلب المجموعة اللاحقة من العناصر. - الترقيم مع التصفية والفرز المعقدين: عند الجمع بين الترقيم ومعلمات التصفية والفرز الديناميكية، تأكد من أن:
- بالنسبة للإزاحة/الحد: العدد الإجمالي
totalItems
يعكس بدقة مجموعة البيانات المصفاة. - بالنسبة للمستند إلى المؤشر: يقوم المؤشر بترميز حالة كل من الفرز والتصفية إذا كانت تؤثر على معنى "التالي". يمكن أن يؤدي هذا إلى تعقيد تصميم المؤشر بشكل كبير. غالبًا، إذا تغيرت عوامل التصفية أو ترتيب الفرز، يتم إعادة تعيين الترقيم إلى "الصفحة الأولى" للعرض الجديد.
- ترقيم GraphQL: لدى GraphQL طريقتها الموحدة الخاصة للتعامل مع الترقيم، والتي يشار إليها غالبًا باسم "الاتصالات". تستخدم عادةً الترقيم المستند إلى المؤشر ولديها هيكل محدد لإرجاع الحواف (العناصر مع المؤشرات) ومعلومات الصفحة. إذا كنت تستخدم GraphQL، التزم باتفاقياته (مثل مواصفات Relay Cursor Connections).
الخلاصة
التنفيذ الصحيح للترقيم أمر أساسي لبناء واجهات برمجة تطبيقات REST قابلة للتطوير وسهلة الاستخدام. بينما الترقيم القائم على الإزاحة/الحد أبسط للبدء به، يوفر الترقيم المستند إلى المؤشر أداءً واتساقًا فائقين لمجموعات البيانات الكبيرة والديناميكية. من خلال فهم التفاصيل التقنية لكل استراتيجية، واختيار الاستراتيجية التي تناسب احتياجات تطبيقك بشكل أفضل، واتباع أفضل الممارسات للتنفيذ وتصميم واجهة برمجة التطبيقات، يمكنك ضمان أن واجهة برمجة التطبيقات الخاصة بك تقدم البيانات بكفاءة لعملائك، بغض النظر عن النطاق. تذكر دائمًا إعطاء الأولوية للتوثيق الواضح ومعالجة الأخطاء القوية لتوفير تجربة سلسة لمستهلكي واجهة برمجة التطبيقات.