Add OPDS2 content negotiation to missing endpoints (PP-3044)#3096
Merged
jonathangreen merged 2 commits intomainfrom Mar 3, 2026
Merged
Add OPDS2 content negotiation to missing endpoints (PP-3044)#3096jonathangreen merged 2 commits intomainfrom
jonathangreen merged 2 commits intomainfrom
Conversation
… detail endpoints These three endpoints were missing mime_types=flask.request.accept_mimetypes in their response calls, causing them to always return OPDS1 regardless of the client's Accept header. This aligns them with the pattern already used by other endpoints like borrow and revoke.
Extract the helper from test_loan.py into tests/fixtures/opds.py to avoid cross-test-file imports. Also fix assert ordering to use actual == expected style in new tests.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3096 +/- ##
==========================================
+ Coverage 93.20% 93.22% +0.02%
==========================================
Files 491 491
Lines 45248 45248
Branches 6222 6222
==========================================
+ Hits 42172 42182 +10
+ Misses 1992 1982 -10
Partials 1084 1084 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
2 tasks
jonathangreen
added a commit
that referenced
this pull request
Mar 3, 2026
## Description Add OPDS2 content negotiation to the navigation endpoint (`/navigation`), the last OPDS feed endpoint that was missing it. Three issues prevented OPDS2 navigation from working: 1. The controller didn't pass `mime_types` to `as_response()` 2. `NavigationFeed.as_response()` unconditionally overrode the response content type to the OPDS1 navigation type 3. Navigation entries used raw OPDS1 content type strings instead of the semantic `LinkContentType` enum, so the OPDS2 serializer passed them through as OPDS1 strings in JSON output Changes: - Add `OPDS_NAVIGATION` to the `LinkContentType` enum with mappings in both serializers - Update `NavigationFeed` to use `LinkContentType` enum values instead of raw OPDS1 strings - Fix `NavigationFeed.as_response()` to only override content type for OPDS1 responses - Pass `mime_types` from the request Accept header in the controller > **Note:** This PR is stacked on #3096. ## Motivation and Context Completes OPDS2 content negotiation support across all OPDS feed endpoints. ## How Has This Been Tested? - New parametrized `test_navigation_content_negotiation` in `test_opds_feed.py` verifying Accept header handling (None, unknown, Atom, OPDS2) - New `test_navigation_resolves_link_content_type` in `test_opds2_serializer.py` verifying `OPDS_NAVIGATION` and `OPDS_FEED` resolve correctly in navigation entries - Updated existing navigation feed tests to assert `LinkContentType` enum values instead of raw strings - All existing navigation tests continue to pass ## Checklist - [x] I have updated the documentation accordingly. - [x] All new and existing tests passed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Add
mime_types=flask.request.accept_mimetypesto three endpoints that were missing OPDS2 content negotiation support:/works/<id>(permalink) — Both the authenticated path (viasingle_entry_loans_feed()) and the unauthenticated path (viaentry_as_response())/recommendations— The feedas_response()call/loans/<id>(detail) — Both the loan and hold paths (viasingle_entry_loans_feed())This aligns these endpoints with the pattern already used by other endpoints like borrow and revoke.
Motivation and Context
These three endpoints always returned OPDS1 responses regardless of the client's
Acceptheader because they did not passmime_typesthrough to their serialization calls. Clients requestingapplication/opds+jsonwould still receive Atom XML responses. This change enables proper OPDS2 content negotiation across all patron-facing endpoints.How Has This Been Tested?
Added parametrized tests for each endpoint covering four
Acceptheader scenarios:Acceptheader → OPDS1 (default)Acceptheader → OPDS1 (fallback)application/atom+xml→ OPDS1application/opds+json→ OPDS2New tests:
test_permalink_content_negotiation(4 variants)test_recommendations_content_negotiation(4 variants)test_detail_loan(4 variants)test_detail_hold(4 variants)All 16 new tests pass, and all existing tests for these endpoints continue to pass.
Checklist