Skip to content

Add an OTP2 GraphQL protocol field and point Puget Sound at it (#1780)#1799

Merged
bmander merged 1 commit into
OneBusAway:mainfrom
bmander:feature/region-otp2-graphql-url
Jul 12, 2026
Merged

Add an OTP2 GraphQL protocol field and point Puget Sound at it (#1780)#1799
bmander merged 1 commit into
OneBusAway:mainfrom
bmander:feature/region-otp2-graphql-url

Conversation

@bmander

@bmander bmander commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #1794. That PR added the OTP 2.x GraphQL trip-planning path but selected it with a usesOtp2GraphQl boolean layered on the single otpBaseUrl. The OBA regions directory doesn't publish that key, and a region's GraphQL host is different from its OTP1 REST host (Puget Sound's REST server is otp.prod.sound.obaweb.org/otp/routers/default/), so the two URLs can't share one field — no region could actually be flipped to OTP2 through the directory.

This replaces the boolean with a dedicated otpBaseGraphqlUrl region field — the mechanism for pointing a region at its OTP2 server on demand, per the maintainer — and points Puget Sound at its OTP2 GraphQL server.

What changed

  • otpBaseGraphqlUrl field end to end: RegionDto (wire) → Room regions.otp_base_graphql_url (v6 migration + exported schema) → Region domain → mappers/adapters. A non-blank value is both the explicit "use OTP2" signal and the OTP mount base — a nullable URL where null/blank means "OTP1 REST". No second boolean to keep in sync.
  • Endpoint resolution: TripRequestBuilder resolves the custom-URL-or-region target once (OtpTarget); Otp2Planner appends OTP2's fixed gtfs GraphQL mount /gtfs/v1 to the base — mirroring the OTP1 path appending /plan, and matching the custom-URL hint that already takes an …/otp base. Selection stays explicit, never sniffed.
  • Puget Sound pointed at OTP2 in the bundled regions seed (otpBaseGraphqlUrl = …/prod/otp). Other bundled regions stay on OTP1 (guarded by RegionsDecodeTest).
  • Bikeshare mode fix: Otp2PlanRequestBuilder sent bare BICYCLE_RENTAL in the access/egress (Transit+Bike) and direct (Bikeshare) mode lists, which OTP2 rejects with a BadRequestError ("BIKE_RENTAL needs to be combined with WALK mode for the same leg"). Both lists now include WALK.
  • Because Add OTP 2.x GraphQL trip-planning support #1794 is unreleased, this revises the v6 schema/migration in place (regions.uses_otp2_graphqlregions.otp_base_graphql_url) rather than shipping a dead column plus a churn migration. Contributors on merged main clear app data once.

Test plan

  • :onebusaway-android:compileObaGoogleDebugKotlin -PwarningsAsErrors=true (+ unit/androidTest source sets) — clean under the strict CI gate
  • Unit tests: Otp2GraphQlEndpointTest (base → /gtfs/v1 append + trailing-slash edge), Otp2PlanRequestBuilderTest (WALK in bike mode lists), RegionsDecodeTest (Puget Sound OTP2, others OTP1), AppDatabaseMigrationTest (v5→v6 adds otp_base_graphql_url)
  • Device-verified end to end (Pixel 7 Pro, Puget Sound): trip planning routes to …/prod/otp/gtfs/v1 and returns itineraries, including a Transit+Bike trip (the bikeshare-mode fix), confirmed against the live OTP 2.x server via the request/response bodies

⚠️ Deploy dependency

Real devices fetch the live regions directory and cache it over the bundled seed. The live directory currently serves Puget Sound otpBaseGraphqlUrl = https://sound-transit-otp.ibi-transit.com/prod/, which 404s — with this client shipped, that stale value would activate OTP2 against a dead URL and break Puget Sound trip planning on the next region refresh. The live directory's Puget Sound otpBaseGraphqlUrl must be updated to the intended OTP2 base (…/otp) before/when this ships.

Closes #1780

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added region-specific OTP2 GraphQL endpoint configuration, enabling OTP2 routing when provided (including Puget Sound).
  • Bug Fixes
    • Improved bike-related trip requests by ensuring required walking legs are included.
    • Fixed OTP2 GraphQL endpoint construction to avoid malformed paths from trailing slashes.
  • Database
    • Updated region settings storage to replace the OTP2 flag with an optional OTP2 GraphQL base URL; existing regions remain on OTP1 until configured.
  • Tests
    • Updated/added coverage for OTP2 endpoint resolution and migration behavior.

@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8176c5cb-de28-46cc-81d4-320d2c66a28e

📥 Commits

Reviewing files that changed from the base of the PR and between ec0a79b and ffba434.

📒 Files selected for processing (22)
  • onebusaway-android/schemas/org.onebusaway.android.database.AppDatabase/6.json
  • onebusaway-android/src/androidTest/java/org/onebusaway/android/database/AppDatabaseMigrationTest.kt
  • onebusaway-android/src/androidTest/java/org/onebusaway/android/mock/MockRegion.java
  • onebusaway-android/src/main/java/org/onebusaway/android/api/adapters/RegionAdapters.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/api/contract/ObaApiModels.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/database/AppDatabase.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/database/Migrations.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/database/oba/ObaEntities.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/directions/util/Otp2PlanRequestBuilder.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/directions/util/TripRequestBuilder.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/region/Region.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/region/RegionMapper.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/settings/AdvancedSettingsScreen.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/settings/AdvancedSettingsViewModel.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/settings/SettingsUiState.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/tripplan/Otp2Planner.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/util/RegionUtils.java
  • onebusaway-android/src/main/res/raw/regions_v3.json
  • onebusaway-android/src/test/java/org/onebusaway/android/api/RegionsDecodeTest.kt
  • onebusaway-android/src/test/java/org/onebusaway/android/directions/util/Otp2PlanRequestBuilderTest.kt
  • onebusaway-android/src/test/java/org/onebusaway/android/region/RegionTestFixtures.kt
  • onebusaway-android/src/test/java/org/onebusaway/android/ui/tripplan/Otp2GraphQlEndpointTest.kt
✅ Files skipped from review due to trivial changes (4)
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/settings/AdvancedSettingsViewModel.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/settings/SettingsUiState.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/settings/AdvancedSettingsScreen.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/database/AppDatabase.kt
🚧 Files skipped from review as they are similar to previous changes (17)
  • onebusaway-android/src/test/java/org/onebusaway/android/ui/tripplan/Otp2GraphQlEndpointTest.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/directions/util/Otp2PlanRequestBuilder.kt
  • onebusaway-android/src/test/java/org/onebusaway/android/directions/util/Otp2PlanRequestBuilderTest.kt
  • onebusaway-android/src/androidTest/java/org/onebusaway/android/database/AppDatabaseMigrationTest.kt
  • onebusaway-android/src/test/java/org/onebusaway/android/api/RegionsDecodeTest.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/api/adapters/RegionAdapters.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/region/Region.kt
  • onebusaway-android/src/test/java/org/onebusaway/android/region/RegionTestFixtures.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/database/oba/ObaEntities.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/region/RegionMapper.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/util/RegionUtils.java
  • onebusaway-android/src/main/res/raw/regions_v3.json
  • onebusaway-android/src/main/java/org/onebusaway/android/directions/util/TripRequestBuilder.kt
  • onebusaway-android/schemas/org.onebusaway.android.database.AppDatabase/6.json
  • onebusaway-android/src/main/java/org/onebusaway/android/database/Migrations.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/tripplan/Otp2Planner.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/api/contract/ObaApiModels.kt

📝 Walkthrough

Walkthrough

OTP2 routing now uses an optional per-region GraphQL URL instead of a boolean flag. Database mappings, request target resolution, GraphQL endpoint construction, Apollo client caching, bundled region data, migration tests, and bicycle mode requests were updated.

Changes

OTP2 GraphQL routing

Layer / File(s) Summary
Region endpoint contract and persistence
onebusaway-android/src/main/java/org/onebusaway/android/api/..., onebusaway-android/src/main/java/org/onebusaway/android/region/..., onebusaway-android/src/main/java/org/onebusaway/android/database/..., onebusaway-android/schemas/..., onebusaway-android/src/main/res/raw/regions_v3.json, onebusaway-android/src/test/...
Region configuration now stores nullable otpBaseGraphqlUrl values, migrates the database schema, maps the value through Room and API models, and configures Puget Sound with a GraphQL endpoint.
OTP target resolution
onebusaway-android/src/main/java/org/onebusaway/android/directions/util/TripRequestBuilder.kt, onebusaway-android/src/main/java/org/onebusaway/android/ui/settings/...
OTP base URL and protocol selection are resolved through a shared target, using custom URL preferences or the selected region’s GraphQL URL.
GraphQL endpoint and client caching
onebusaway-android/src/main/java/org/onebusaway/android/ui/tripplan/Otp2Planner.kt, onebusaway-android/src/test/java/org/onebusaway/android/ui/tripplan/Otp2GraphQlEndpointTest.kt
OTP2 planning appends /gtfs/v1 to the base URL, normalizes trailing slashes, and caches Apollo clients by resolved endpoint.
OTP2 bicycle mode handling
onebusaway-android/src/main/java/org/onebusaway/android/directions/util/Otp2PlanRequestBuilder.kt, onebusaway-android/src/test/java/org/onebusaway/android/directions/util/Otp2PlanRequestBuilderTest.kt
Bike rental access, egress, and direct mode lists now include both WALK and BICYCLE_RENTAL, with updated expectations.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant RegionConfig
  participant TripRequestBuilder
  participant Otp2Planner
  participant ApolloClient
  RegionConfig->>TripRequestBuilder: provide otpBaseGraphqlUrl
  TripRequestBuilder->>TripRequestBuilder: resolve OTP target and protocol
  TripRequestBuilder->>Otp2Planner: pass OTP2 base URL
  Otp2Planner->>Otp2Planner: append /gtfs/v1
  Otp2Planner->>ApolloClient: create or reuse client for endpoint
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 63.64% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Linked Issues check ❓ Inconclusive The protocol field, endpoint selection, region wiring, and OTP2 request tests align with #1780, but response-parsing coverage isn't shown. Add or reference the GraphQL response-mapping and end-to-end trip-planning tests needed to verify the full OTP2 flow from #1780.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main OTP2 GraphQL region-field change and Puget Sound seed update.
Out of Scope Changes check ✅ Passed The remaining edits are supporting schema, mapper, and test updates for the OTP2 rollout, with no clear unrelated changes.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…sAway#1780)

OneBusAway#1794 selected OTP2 with a `usesOtp2GraphQl` boolean layered on the single
`otpBaseUrl` — but the OBA regions directory doesn't publish that key, and a
region's GraphQL endpoint is a different host than its OTP1 REST server (Puget
Sound's REST server is otp.prod.sound.obaweb.org/otp/routers/default), so the two
URLs can't share one field. The directory carries a dedicated `otpBaseGraphqlUrl`
key instead — the mechanism for pointing a region at its OTP2 server on demand.

Replace the boolean with an `otpBaseGraphqlUrl` field end to end (RegionDto →
Room → Region): a non-blank value is both the explicit OTP2 signal and the OTP
mount base. `TripRequestBuilder.usesOtp2`/`formattedOtpBaseUrl` derive from it,
and `Otp2Planner` appends OTP2's fixed `/gtfs/v1` gtfs GraphQL mount to reach the
endpoint — mirroring the OTP1 path appending `/plan`, and matching the custom-URL
hint that already takes an `…/otp` base. Selection stays explicit, never sniffed.

Point Puget Sound at its OTP2 GraphQL server in the bundled regions seed
(otpBaseGraphqlUrl = …/prod/otp; the base serves the OTP root, base + /gtfs/v1
serves GraphQL — both verified live). Other bundled regions stay on OTP1.

Fix the OTP2 bikeshare mode encoding: `Otp2PlanRequestBuilder` sent bare
BICYCLE_RENTAL in the access/egress (Transit+Bike) and direct (Bikeshare) mode
lists, which OTP2 rejects with a BadRequestError ("BIKE_RENTAL needs to be
combined with WALK mode for the same leg"). Both lists now include WALK, verified
against the live server. Device-verified end to end (Pixel 7 Pro, Puget Sound).

Because OneBusAway#1794 is unreleased, this revises the v6 schema/migration in place
(regions.uses_otp2_graphql → regions.otp_base_graphql_url) rather than shipping a
dead column plus a churn migration; contributors on merged main clear app data.

NOTE: the live regions directory must be repointed to match before this ships —
it currently serves Puget Sound otpBaseGraphqlUrl = sound-transit-otp.ibi-
transit.com/prod/, which 404s, and would break Puget Sound trip planning as soon
as a device refreshes regions over the bundled seed.
@bmander
bmander force-pushed the feature/region-otp2-graphql-url branch from ec0a79b to ffba434 Compare July 12, 2026 02:49
@bmander
bmander merged commit 0b8975b into OneBusAway:main Jul 12, 2026
3 checks passed
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.

Add OTP 2.x GraphQL trip-planning support (on the new domain model)

1 participant