Welcome back! In the previous lessons, you learned how to build the foundation of a book catalog and track user reading progress. Now, we will take your API to the next level by adding advanced sorting and analytics features. These improvements will help users find books more easily and allow you to provide valuable insights about each book in your catalog.
Sorting lets users organize the catalog in ways that are most useful to them, such as by title, author, or how much progress readers have made. Analytics gives you a deeper look at how books are being read, such as the average progress of all readers or the completion rate for a book. These features are common in real-world applications and make your API much more powerful and user-friendly.
Here we allow clients to request sorting by average progress across readers.
What changed
- Added
'avgProgress'to the allowedsortByenum. - Left all other parameters intact so existing clients keep working.
Why
- Clients can ask the catalog to rank books by how far readers get, a stronger engagement proxy than simple recency or title.
This DTO change is minimal but important: it creates a typed contract for a new sort dimension without altering route shape. Because validation is centralized here, the service can trust that sortBy='avgProgress' is intentional and safe to handle.
To make your catalog more useful, you can let users sort the list of books by different fields. This is done using the sortBy and order query parameters in your API.
Here’s how you might call the endpoint to sort books by title in ascending order:
Or, to sort by avgProgress in descending order:
In your code, this is handled in the findAll method of your service:
Explanation:
- The
sortByparameter lets you choose which field to sort on (liketitle,author, oravgProgress). - The
orderparameter can be (ascending) or (descending).
What changed
- When
sortBy='avgProgress', we aggregate sessions by bookId and compute the mean progress ratio:avgProgress = totalCurrentPages / (totalPages * readers) (0–1). - Books with
totalPages = 0orreaders = 0safely default to0to avoid division by zero. - The sorter branches: numeric compare for
avgProgress, string compare for other fields.
Why
- Sorting by a computed metric requires a pre-pass. Doing this server-side keeps clients thin and guarantees consistent semantics.
This approach scales with catalog size because we aggregate only once, then sort. The definition intentionally weights readers equally (average of ratios) rather than pages, so a few power readers don’t dominate the signal. Returning pagination metadata unchanged keeps the endpoint UI-ready.
When your catalog grows, you don’t want to return every book at once. Pagination helps you break up the results into pages, making it easier to browse.
You can use the page and pageSize query parameters:
This request will return the second page of results, with one book per page.
Here’s how pagination is handled in your service:
Explanation:
pagetells the API which page of results to return (starting from 1).pageSizecontrols how many books are on each page.- The code calculates which items to return based on these values.
Example Output:
If you request /books?page=2&pageSize=1, you might get:
Your API can also provide analytics for each book, such as how many people are reading it, the average page reached, and the completion rate. This is useful for both users and admins to see how popular or engaging a book is.
To get analytics for a book, use the following endpoint:
Here’s the relevant code:
Explanation:
- The method finds all reading sessions for the given book.
- It calculates:
readers: How many people are reading the book.avgCurrentPage: The average page reached by all readers.completionRate: The percentage of readers who finished the book.avgProgressPct: The average progress as a percentage.
This endpoint complements catalog sorting: avgProgressPct mirrors the value used for ranking, while readers and add context. Surfacing both the breadth (how many readers) and depth (how far they get) gives a balanced view of engagement.
These calls use only public routes; no authentication is required.
What to look for
- The first call returns a paginated list with items ranked by highest avgProgress first.
- The second call returns stats like:
- If there are few/no sessions, values will be near
0. As readers update progress (from the Shelf unit), these values increase.
- avgProgress (0–1): Mean fraction of pages reached across readers. Great for “trending by engagement” lists. Preferable to raw average page because it normalizes by book length.
- readers (count): Popularity breadth. Pair with
avgProgressto avoid small-sample anomalies (e.g., 1 reader at 100%). - completionRate (0–1): Signal of finishability/quality; useful for “Most Completed” carousels.
- avgCurrentPage (pages): Human-readable progress; useful in admin dashboards to spot consistent drop-offs (e.g., chapters with high abandonment).
Tip: When ranking for end users, consider a composite like
avgProgress * log(1 + readers)to balance depth and breadth (outside the scope of this unit but easy to add later).
In this lesson, you learned how to make your book catalog more powerful by adding sorting, pagination, and per-book analytics. You saw how to use query parameters to control sorting and paging, and how to get useful statistics for each book.
You enabled two powerful analytics features: catalog sorting by avgProgress and per-book stats that quantify engagement. Together they support better discovery, editorial decisions, and future features like recommendations—all while keeping clients thin and the API contract typed and predictable.
You are now ready to practice these features in the exercises that follow. Try out different combinations of sorting, paging, and analytics to see how they work in real scenarios.
Congratulations on reaching the end of this course! You have built a flexible and insightful book catalog API. Keep experimenting and applying these skills to your own projects. Well done!
