Skip to content

Support RDF/XML and Turtle content negotiation; fix wildcard Accept 500#1518

Open
Copilot wants to merge 3 commits intomasterfrom
copilot/fix-rdf-turtle-content-negotiation
Open

Support RDF/XML and Turtle content negotiation; fix wildcard Accept 500#1518
Copilot wants to merge 3 commits intomasterfrom
copilot/fix-rdf-turtle-content-negotiation

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 17, 2026

Accept: */* and no-Accept requests were returning 500 due to Rails unsafe-redirect protection blocking cross-host redirects in the format.html branch. Additionally, application/rdf+xml and text/turtle were not supported as representations — both redirected 303 instead of returning content.

Changes

  • Unsafe redirect fix (app/controllers/index_controller.rb)

    • Added allow_other_host: true to format.html redirect — matches the already-correct rescue branch; eliminates 500 for wildcard/no-Accept requests
  • RDF/XML + Turtle MIME registration (config/initializers/mime_types.rb)

    • application/rdf+xml:rdf_xml
    • text/turtle:turtle (with application/x-turtle as alias)
    • Renderers call obj.rdf_xml / obj.turtle from Bolognese's RdfXmlWriter/TurtleWriter, already included in Doi via Crosscitable — no network calls, no new dependencies
  • Controller wiring (app/controllers/index_controller.rb)

    • Added :rdf_xml and :turtle to the format.any(...) block
  • Link-form routes (config/routes.rb)

    get "/application/rdf+xml/:id",  to: "index#show", constraints: { id: /.+/ }, defaults: { format: :rdf_xml }
    get "/application/x-turtle/:id", to: "index#show", constraints: { id: /.+/ }, defaults: { format: :turtle }
    get "/text/turtle/:id",          to: "index#show", constraints: { id: /.+/ }, defaults: { format: :turtle }
  • Request specs (spec/requests/index_spec.rb)

    • Header-based and link-form tests for application/rdf+xml, text/turtle, application/x-turtle
    • Wildcard Accept: */* guard (must not return 500)
Original prompt

Create a PR in datacite/lupo to fully support RDF/XML and Turtle content negotiation (both header-based and link-form routes) without making network calls, and fix wildcard/no-Accept redirect failures.

Context / current behavior (stage testing):

  • Most content negotiation formats already work.
  • Accept: */* and requests with no Accept header currently return 500 due to Rails unsafe redirect protection when redirecting to doi.url.
  • Accept: application/rdf+xml and Accept: text/turtle currently redirect (303) instead of returning RDF.

Requirements:

  1. Fix unsafe redirect for HTML fallback in app/controllers/index_controller.rb:

    • In format.html branch of IndexController#show, redirect to doi.url must include allow_other_host: true (to avoid 500).
    • Keep status :see_other.
  2. Add RDF/XML + Turtle response support in Lupo (no network calls):

    • Support RDF/XML application/rdf+xml (format symbol :rdf_xml).
    • Support Turtle for BOTH text/turtle and legacy application/x-turtle (format symbol :turtle).
    • Implement header-based negotiation (GET /:doi with Accept:) and link-form routes (GET /application/rdf+xml/:id, GET /application/x-turtle/:id, GET /text/turtle/:id).
  3. No network calls:

    • Do not fetch metadata from external APIs.
    • Use the DOI record already available in Lupo, converting it to RDF using local code.
  4. Implementation approach guidance:

    • Lupo already depends on RDF-related gems (rdf, rdf-rdfxml, rdf-turtle) per Gemfile.lock, and DataCite uses Bolognese writers in the legacy CN service.
    • Prefer leveraging existing Bolognese conversion if already present in Lupo, but do not add external HTTP calls.
    • If Bolognese is not currently a dependency, you may add it as a gem dependency if needed and reasonable, but keep change minimal.
  5. Update MIME types and renderers:

    • Ensure config/initializers/mime_types.rb registers:
      • application/rdf+xml => :rdf_xml
      • application/x-turtle => :turtle
      • text/turtle => :turtle
    • Add renderers for :rdf_xml and :turtle.
  6. Update IndexController#show:

    • Include :rdf_xml and :turtle in the format.any(...) block that renders render request.format.to_sym => doi.
  7. Add routes for link-form content negotiation:

    • In config/routes.rb, add GET routes mapping to IndexController#show with defaults:
      • /application/rdf+xml/:id => format :rdf_xml
      • /application/x-turtle/:id => format :turtle
      • /text/turtle/:id => format :turtle
    • Ensure constraints: { id: /.+/ } consistent with other CN routes.
  8. Tests:

    • Add request specs that cover:
      • GET /:doi with Accept: application/rdf+xml returns 200 and Content-Type contains application/rdf+xml.
      • GET /:doi with Accept: application/x-turtle returns 200 and Content-Type contains application/x-turtle OR text/turtle (depending on mime registration) and body contains Turtle-like content (e.g., @prefix schema:).
      • GET /:doi with Accept: text/turtle returns 200 and turtle body.
      • Link-form routes return 200 and correct Content-Type:
        • /application/rdf+xml/:doi
        • /application/x-turtle/:doi
        • /text/turtle/:doi
      • GET /:doi with Accept: */* does not 500 and redirects (302/303) to doi.url.
      • GET /:doi with no Accept header does not 500 and redirects.
  9. PR description requirements:

    • Do NOT include any prompt text.
    • PR description must explain what changed and why (parity with resolver, keep RDF/Turtle support, fix unsafe redirect regression).

Notes:

  • Use DOI fixtures/factories already in Lupo tests; pick a findable DOI with a URL that is external host (e.g., http://datacite.org/) to exercise redirect behavior.
  • Ensure that RDF/Turtle generation uses local DOI metadata and does not require network.

The following is the prior conversation context from the user's chat exploration (may be truncated):

User: Running Lupo Content Negotiation Compliance Tests
Base: https://api.stage.datacite.org

======================================
Testing DOI: 10.81360/BIFURCATED
Base: https://api.stage.datacite.org
Require link routes: 0

✅ PASS: DataCite XML (header) (status=200)
✅ PASS: DataCite XML CT (header) (ct=application/vnd.datacite.datacite+xml; charset=utf-8)
✅ PASS: DataCite XML (link) supported
✅ PASS: DataCite JSON (header) (status=200)
✅ PASS: DataCite JSON CT (header) (ct=application/vnd.datacite.datacite+json; charset=utf-8)
✅ PASS: DataCite JSON (link) supported
✅ PASS: JSON-LD (header) (status=200)
✅ PASS: JSON-LD CT (header) (ct=application/vnd.schemaorg.ld+json; charset=utf-8)
✅ PASS: JSON-LD (link) supported
✅ PASS: CSL JSON (header) (status=200)
✅ PASS: CSL JSON CT (header) (ct=application/vnd.citationstyles.csl+json; charset=utf-8)
✅ PASS: CSL JSON (link) supported
✅ PASS: Codemeta (header) (status=200)
✅ PASS: Codemeta CT (header)...

This pull request was created from Copilot chat.

Copilot AI and others added 2 commits April 17, 2026 09:08
…ct for HTML fallback

Agent-Logs-Url: https://github.com/datacite/lupo/sessions/78ba3e36-39d3-454a-89b1-792566149549

Co-authored-by: ashwinisukale <1137325+ashwinisukale@users.noreply.github.com>
Agent-Logs-Url: https://github.com/datacite/lupo/sessions/78ba3e36-39d3-454a-89b1-792566149549

Co-authored-by: ashwinisukale <1137325+ashwinisukale@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix RDF/XML and Turtle content negotiation issues Support RDF/XML and Turtle content negotiation; fix wildcard Accept 500 Apr 17, 2026
Copilot AI requested a review from ashwinisukale April 17, 2026 09:12
@ashwinisukale ashwinisukale marked this pull request as ready for review April 17, 2026 09:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants