Data Fetching and Hydra Pagination
The Back-Office communicates with a Symfony / API Platform backend that returns data in Hydra JSON-LD format. List endpoints return paginated collections, but because the Opal Table component handles pagination, sorting, and filtering on the client side, the Back-Office needs to fetch all items upfront before handing them to the table. ThefetchAllHydraItems helper centralizes this multi-page fetching logic so that individual stores and views do not need to implement it themselves.
The Problem It Solves
Without a shared helper, every Pinia store and list view had to:- Send a first request with
page=1&itemsPerPage=100. - Read
hydra:totalItemsfrom the response to calculate how many pages exist. - Loop through remaining pages, accumulating
hydra:memberarrays. - Manually extract and return the combined items and total count.
The fetchAllHydraItems Helper
Location: bo/src/services/api/client.ts
Signature
Parameters
| Parameter | Type | Description |
|---|---|---|
path | string | The API endpoint path (e.g., '/admin/articles') |
params | Record<string, any> | Optional query parameters for filtering (e.g., { status: 'published' }) |
options | RequestOptions | Optional request options passed through to the underlying get() call |
Return Value
| Field | Type | Description |
|---|---|---|
items | T[] | All items from all pages, concatenated into a single array |
total | number | The total item count reported by the API (hydra:totalItems) |
How It Works
- First request — Sends
page=1&itemsPerPage=100(merged with any caller-provided params) and reads the total count fromhydra:totalItems. - Remaining pages in parallel — If the total exceeds 100 items, the helper calculates how many additional pages are needed and fetches them all concurrently using
Promise.all. This is significantly faster than sequential fetching for large collections. - Result assembly — All
hydra:memberarrays are concatenated and returned alongside the total count.
The helper always requests 100 items per page, which is the maximum supported by the API. Callers should not pass
page or itemsPerPage in their params — the helper manages pagination internally.Usage in Pinia Stores
Stores usefetchAllHydraItems in their list/fetch actions, passing only the filter parameters relevant to the entity. The helper handles all pagination concerns.
Example: Articles Store
articles, pages, blocks, users):
- Build a
paramsobject from the active filters. - Call
fetchAllHydraItemswith the entity endpoint and params. - Assign the returned
itemsandtotalto the store’s reactive state.
Usage in List Views (Without a Store)
Some simpler entities (categories, tags, redirects) do not have dedicated Pinia stores. Their list views importfetchAllHydraItems directly.
Example: CategoryListView
When to Use This Helper
UsefetchAllHydraItems whenever you need to display all items from a Hydra collection endpoint in an Opal Table or similar client-side paginated component.
Use it when:
- You are building a new list view backed by a Hydra collection endpoint.
- The UI component (Opal Table) handles pagination, sorting, or filtering on the client side.
- You need all items loaded upfront rather than fetched page by page as the user navigates.
- You need server-side pagination (i.e., fetching one page at a time as the user navigates).
- The endpoint does not return Hydra JSON-LD format (
hydra:member/hydra:totalItems). - You only need a single item (use
get()directly instead).
Adding a New List View: Checklist
When creating a list view for a new entity, follow this pattern:Decide on state management
If the entity needs CRUD operations and shared state, create a Pinia store. If it only needs a simple list, import
fetchAllHydraItems directly in the view component.Build filter params
Construct a
Record<string, unknown> object from the user’s active filters. Do not include page or itemsPerPage.Call fetchAllHydraItems
Pass the API path (e.g.,
'/admin/my-entity'), your filter params, and the entity type as the generic parameter.API Service Functions vs. fetchAllHydraItems
The codebase has two layers for API communication:| Layer | Location | Purpose |
|---|---|---|
| Service functions | services/api/<entity>.ts | Typed wrappers for individual CRUD operations (getArticle, createArticle, updateArticle, deleteArticle) |
| fetchAllHydraItems | services/api/client.ts | Shared helper for fetching complete paginated collections |
ListQueryParams for their list operations, which is appropriate for targeted single-page requests. For full-collection fetching, stores and views call fetchAllHydraItems directly, bypassing the service layer’s list functions. This keeps service function signatures clean while giving stores the flexibility to pass arbitrary filter parameters.