Skip to content
Extending/Response strategies

Response strategies

A response strategy turns a raw body into a PaginatedCollection. There are three starting points, and picking the right one is usually the whole job.

Everything at the top level, named:

{ "data": [], "current_page": 2, "last_page": 6, "total": 57 }

Extend AbstractFlatResponseStrategy with an empty body. The base reads each field by the name in ResponseOptions.

Used by Laravel and Spatie.

Metadata inside a sub-object:

{ "data": [], "meta": { "pagination": { "page": 2, "pageCount": 6 } } }

Extend AbstractDotPathResponseStrategy. Paths in ResponseOptions become dotted: meta.pagination.page.

It also derives from and to arithmetically when the backend omits them.

Used by Strapi, JSON:API, Payload, PocketBase, Sieve and others.

Implement IResponseStrategy directly when the shape is not a lookup — cursor URLs to parse, headers to read, or a bare array body.

export class MyResponseStrategy implements IResponseStrategy {
public paginate<T extends PaginatedObject>(
response: RawResponse,
options: ResponseOptions,
headers?: HeaderBag,
): PaginatedCollection<T> {
// …
}
}

Used by DRF (cursor URLs), OData (@odata.nextLink), PostgREST and WordPress (headers).

PostgREST and the WordPress REST API return rows directly, with metadata in headers. RawResponse models both shapes:

type RawResponse = Record<string, unknown> | readonly unknown[];

Read headers through readHeader(), which accepts anything with a .get() accessor or a plain object, without importing a framework:

import { readHeader } from '@qubeejs/core';
const range = readHeader(headers, 'Content-Range'); // '0-24/57'

readPath() and its typed variants handle both body shapes and missing keys:

import { readNumber, readRows, readString } from '@qubeejs/core';
readRows<T>(response, options.data);
readNumber(response, options.total);
readString(response, options.nextPageUrl);