Careeroza
Paging a REST Endpoint
Pageable as a Controller Parameter
Spring Data web support binds ?page=&size=&sort= query parameters to a Pageable automatically. @PageableDefault sets defaults.
@RestController
@RequestMapping("/api/products")
@RequiredArgsConstructor
public class ProductController {
private final ProductRepository products;
@GetMapping
public PagedModel<ProductCardDto> list(
@RequestParam String category,
@PageableDefault(size = 20, sort = "id", direction = Sort.Direction.DESC) Pageable pageable) {
return new PagedModel<>(products.findByCategoryName(category, pageable).map(ProductCardDto::from));
}
}Configuration
Limit page size globally so nobody can ask for size=100000:
application.properties
spring.data.web.pageable.max-page-size=100
spring.data.web.pageable.default-page-size=20Request and Response
Example
curl "localhost:8080/api/products?category=Books&page=1&size=3&sort=price,asc"Example output
HTTP/1.1 200 OK
Content-Type: application/json
{
"content": [
{"id": 64, "name": "Atomic Habits", "price": 399.00},
{"id": 71, "name": "The Psychology of Money", "price": 349.00},
{"id": 52, "name": "Wings of Fire", "price": 299.00}
],
"page": {"size": 3, "number": 1, "totalElements": 41, "totalPages": 14}
}Note: Returning a raw PageImpl from a controller makes Spring Data 3.3+ log a warning, because its JSON shape is not a stable contract. Wrap it in PagedModel (as above) or enable @EnableSpringDataWebSupport(pageSerializationMode = VIA_DTO).
Practice
Exercise: Add an endpoint GET /api/me/orders that returns the current user's orders as a Slice, newest first, 10 per page by default.
Show answer
// repository
Slice<OrderSummaryView> findByUserId(Long userId, Pageable pageable);
// controller
@GetMapping("/api/me/orders")
public Slice<OrderSummaryView> myOrders(@AuthenticationPrincipal ShopUser me,
@PageableDefault(size = 10, sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable) {
return orderRepository.findByUserId(me.getId(), pageable);
}