Migrate existing trending_books_api endpoint to FastAPI and added tests#12000
Conversation
|
It should be the exact same url don't prepend internal. |
f4d7874 to
988f6fe
Compare
|
Fixed - removed the |
8891257 to
89bf6b2
Compare
RayBB
left a comment
There was a problem hiding this comment.
It's a good start. Left some initial feedback.
8a68b89 to
8891257
Compare
bhardwajparth51
left a comment
There was a problem hiding this comment.
Hey @RayBB, thanks for the feedback! I've pushed an update addressing your points: I switched to the shared Pagination model, removed the deprecated days param, and cleaned up the logger, extra docstrings, and responses block. Let me know if there's anything else
b846e9a to
363ca83
Compare
|
Two quick notes for your review/testing:
|
363ca83 to
f7b21e7
Compare
|
Hey @RayBB, just checking in on this when you get a chance! |
RayBB
left a comment
There was a problem hiding this comment.
Good start with this. In general it looks close.
There's a bug thought.
Steps to reproduce:
- Visit: http://localhost:8080/books/OL24152177M/Robinson_Crusoe
- Click want to read
- Visit http://localhost:18080/trending/now.json
- See error
Unfortunately, in this case, we should probably just have it keep running on the main thead. One day we'll be able to have an async postgres driver but we are not there yet.
- Switched trending_books_api to synchronous execution to preserve web.ctx - Centralized parameters into TrendingRequestParams pydantic model - Moved parse_fields_string to shared fastapi/models.py - Expanded test suite to 45 cases covering exhaustive field combinations - Enforced 1000 limit constraint
f7b21e7 to
3416df0
Compare
…migration # Conflicts: # openlibrary/fastapi/models.py # openlibrary/fastapi/search.py
|
Hey @RayBB, I've addressed all the requested changes:
All 45 tests passing. Ready for your review! |
RayBB
left a comment
There was a problem hiding this comment.
Can you please provide a video of this working on
http://localhost:8080/trending/now.json
and
http://localhost:18080/trending/now.json
It doesn't work at all when I open it.
Be sure to add at least one book to a want to read list or rating first so there's data.
|
Note on |
|
Here is the screen recording showing parity between legacy (8080) and FastAPI (18080) — added 3 books to Want to Read (Alice's Adventures in Wonderland, Gulliver's Travels, Robinson Crusoe) and both endpoints return identical results. |
|
Hey @RayBB, just checking in — all 45 tests passing and the screen recording shows parity between legacy and FastAPI. Let me know if there's anything else to address! |
for more information, see https://pre-commit.ci
for more information, see https://pre-commit.ci
RayBB
left a comment
There was a problem hiding this comment.
It looks very close but two questions for you!
openlibrary/fastapi/internal/api.py
Outdated
| True, | ||
| description="Sort results by total log count (most-logged first). Defaults to True, matching the legacy endpoint behaviour.", |
There was a problem hiding this comment.
The Issue: The FastAPI version defaults sort_by_count to True, but the legacy endpoint defaults it to False. The comment even incorrectly claims "Defaults to True, matching the legacy endpoint behaviour."
Impact: Users who don't explicitly specify the sort_by_count parameter will get different sorting behavior between the legacy and FastAPI endpoints, breaking backward compatibility.
| """Fetch trending books for the given period.""" | ||
| # ``period`` is always a key in SINCE_DAYS — guaranteed by the Literal type above. | ||
| since_days: int | None = SINCE_DAYS[period] | ||
| web.ctx.site = site_ctx.get() |
There was a problem hiding this comment.
Can you help me figure out why we need this here? In general we want to avoid using web.ctx.site in fastapi. However, it seems that without this we get a bug. Why is that? Is there any way we can avoid this? It would be very helfpul to understand this
There was a problem hiding this comment.
Ah it seems this is in schemes/works.py line 651
things = cast(list[Work | Edition], web.ctx.site.get_many(keys))
We could change that to site.get now but it does seem to touch quite a bit of code so maybe we should do it in a separate PR.
There was a problem hiding this comment.
Yeah exactly, traced it to schemes/works.py line 651 — web.ctx.site.get_many(keys) inside add_non_solr_fields. FastAPI never sets up web.ctx.site so without the bridge it just blows up. Makes sense to keep the refactor in a separate PR
RayBB
left a comment
There was a problem hiding this comment.
Excellent work here. I pushed a few small tweeks up but overall this is exactly what we need!
Testing the following urls to confirm it's the same in fastapi and web.py:
- https://testing.openlibrary.org/trending/daily.json
- https://testing.openlibrary.org/trending/daily.json?limit=10
- https://testing.openlibrary.org/trending/daily.json?sort_by_count=false
- https://testing.openlibrary.org/trending/daily.json?minimum=5
- https://testing.openlibrary.org/trending/daily.json?days=30
- https://testing.openlibrary.org/trending/daily.json?hours=1
- https://testing.openlibrary.org/trending/daily.json?fields=key,title
- https://testing.openlibrary.org/trending/monthly.json?limit=50&page=1&sort_by_count=false&fields=key,title,ratings_average,ratings_count
|
@bhardwajparth51 congrats on this one. It was a littler trickier than it looked at first. Please closely review the changes I added to your branch before merging so you can learn a bit more! |
Part of #11999
Migrates the
/trending/{period}.jsonendpoint from the legacyweb.pyto FastAPI at/trending/{period}.json.Technical
/trending/{period}.jsoninopenlibrary/fastapi/internal/api.pyQueryannotations so params likehours,page, andlimitare bounds-checked and cast to the right types automatically — no manual parsing neededSolrWorkPydantic model and usedresponse_model_exclude_none=Trueto match the legacy output faithfully, including intentionally droppingdaysfrom theforeverresponseasyncio.to_thread(get_trending_books, ...)call in atry/exceptso any database failure comes back as a clean 502 Bad Gateway instead of a raw 500fastapi_clientfixture fromconftest.pyand leaned heavily on@pytest.mark.parametrizeto cover all periods and query param combinations without repetition. Also added atest_trending_comparison.shintegration script to verify 1:1 parity with the legacy endpointTesting
docker compose exec web pytest openlibrary/tests/fastapi/test_trending.py -vStakeholders
@RayBB