Pagination, Search, and Sorting
Backend
Query Parameters
All list endpoints accept:
page (int, default: 1) — current page number
pageSize (int, default: 10) — items per page
search (string?, optional) — text to filter results
sortBy (string, default varies) — field name to sort by
sortDirection (string, default: "asc") — asc or desc
Default Sort Orders
- Patients: by
lastName then firstName
- Doctors: by
specialty then lastName
- Exams: by
scheduledDate
Store Implementation
public (IReadOnlyList<T> Items, int TotalCount) GetPaged(int page, int pageSize, string sortBy, string sortDirection)
{
var totalCount = _collection.Count();
var items = ApplySort(_collection.FindAll(), sortBy, sortDirection)
.Skip((page - 1) * pageSize).Take(pageSize).ToList();
return (items, totalCount);
}
public (IReadOnlyList<T> Items, int TotalCount) SearchPaged(string search, int page, int pageSize, string sortBy, string sortDirection)
{
var filtered = _collection.FindAll()
.Where(item => /* case-insensitive string matching on relevant fields */)
.ToList();
var totalCount = filtered.Count;
var items = ApplySort(filtered, sortBy, sortDirection)
.Skip((page - 1) * pageSize).Take(pageSize).ToList();
return (items, totalCount);
}
Response Structure
public record {Entity}ListResponse(
IReadOnlyList<{Entity}Response> Items,
PaginationInfo Pagination,
SortInfo Sort,
IReadOnlyList<Link> Links);
Pagination Links
Use PaginationLinks.Build(basePath, page, pageSize, totalPages, search, sortBy, sortDirection, additionalLinks).
Frontend
List Page Pattern
- State:
page, pageSize, search, sortBy, sortDirection, data.
- Fetch with query params appended to the HATEOAS-discovered base URL.
- MUI
TablePagination for page navigation.
- MUI
TextField + Button for search input.
- MUI
TableSortLabel on column headers for sort toggle.
- Clicking a column header cycles: default → asc → desc.
1---2name: pagination-search-and-sorting3description: Implement server-side pagination, search filtering, and column sorting across API endpoints and frontend list pages.4---56# Pagination, Search, and Sorting78## Backend910### Query Parameters11All list endpoints accept:12- `page` (int, default: 1) — current page number13- `pageSize` (int, default: 10) — items per page14- `search` (string?, optional) — text to filter results15- `sortBy` (string, default varies) — field name to sort by16- `sortDirection` (string, default: "asc") — `asc` or `desc`1718### Default Sort Orders19- **Patients**: by `lastName` then `firstName`20- **Doctors**: by `specialty` then `lastName`21- **Exams**: by `scheduledDate`2223### Store Implementation24```csharp25public (IReadOnlyList<T> Items, int TotalCount) GetPaged(int page, int pageSize, string sortBy, string sortDirection)26{27 var totalCount = _collection.Count();28 var items = ApplySort(_collection.FindAll(), sortBy, sortDirection)29 .Skip((page - 1) * pageSize).Take(pageSize).ToList();30 return (items, totalCount);31}3233public (IReadOnlyList<T> Items, int TotalCount) SearchPaged(string search, int page, int pageSize, string sortBy, string sortDirection)34{35 var filtered = _collection.FindAll()36 .Where(item => /* case-insensitive string matching on relevant fields */)37 .ToList();38 var totalCount = filtered.Count;39 var items = ApplySort(filtered, sortBy, sortDirection)40 .Skip((page - 1) * pageSize).Take(pageSize).ToList();41 return (items, totalCount);42}43```4445### Response Structure46```csharp47public record {Entity}ListResponse(48 IReadOnlyList<{Entity}Response> Items,49 PaginationInfo Pagination,50 SortInfo Sort,51 IReadOnlyList<Link> Links);52```5354### Pagination Links55Use `PaginationLinks.Build(basePath, page, pageSize, totalPages, search, sortBy, sortDirection, additionalLinks)`.5657## Frontend5859### List Page Pattern60- State: `page`, `pageSize`, `search`, `sortBy`, `sortDirection`, `data`.61- Fetch with query params appended to the HATEOAS-discovered base URL.62- MUI `TablePagination` for page navigation.63- MUI `TextField` + `Button` for search input.64- MUI `TableSortLabel` on column headers for sort toggle.65- Clicking a column header cycles: default → asc → desc.