Build Pagination Link Headers (RFC 8288)

Build RFC 8288 Link headers for paginated APIs with self, first, previous, next and last relations and validated page bounds.

TypescriptData Fetching

Code

snippet
export function buildPaginationLinkHeader(
  baseUrl: string,
  options: { page: number; perPage: number; total: number },
): string {
  if (typeof baseUrl !== "string" || baseUrl.length === 0) {
    throw new TypeError("baseUrl must be a non-empty string");
  }
  const { page, perPage, total } = options;
  if (!Number.isInteger(page) || page < 1) {
    throw new RangeError("page must be a positive integer");
  }
  if (!Number.isInteger(perPage) || perPage < 1) {
    throw new RangeError("perPage must be a positive integer");
  }
  if (!Number.isInteger(total) || total < 0) {
    throw new RangeError("total must be a non-negative integer");
  }
  const lastPage = Math.max(1, Math.ceil(total / perPage));
  if (page > lastPage) throw new RangeError("page must not exceed the last page");
  const base = new URL(baseUrl);
  const link = (target: number, rel: string): string => {
    const url = new URL(base);
    url.searchParams.set("page", String(target));
    url.searchParams.set("limit", String(perPage));
    return "<" + url.toString() + '>; rel="' + rel + '"';
  };
  const parts = [link(page, "self"), link(1, "first")];
  if (page > 1) parts.push(link(page - 1, "prev"));
  if (page < lastPage) parts.push(link(page + 1, "next"));
  parts.push(link(lastPage, "last"));
  return parts.join(", ");
}