Fix GoingToCamp KeyError and add attribute filtering support - #398
Fix GoingToCamp KeyError and add attribute filtering support#398javamonkey79 wants to merge 2 commits into
Conversation
The GoingToCamp API has changed its /api/maps endpoint to no longer provide per-facility mapId lookups, causing a KeyError when listing campgrounds. This fix: - Uses rootMapId from /api/resourceLocation response instead of looking up mapId from /api/maps (which no longer has it) - Adds root_map_id field to ResourceLocation model - Gracefully handles the now-404 /api/resource/details endpoint by returning fallback site data so availability searches still work Fixes juftin#377 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The GoingToCamp API supports filtering by site attributes (like electric
hookups) via the filterData parameter, but it requires:
1. Using 'enumValues' instead of 'values' in the filter objects
2. JSON-encoding the filterData as a string
This change:
- Adds attribute_filters parameter to list_site_availability()
- Properly formats filterData with enumValues and JSON encoding
- Adds attribute_filters to SearchGoingToCamp class
- Adds attribute_filters to YAML config model for use with --yaml-config
Example YAML config for searching electric RV sites:
provider: GoingToCamp
recreation_area: 3
campgrounds: -2147483565
attribute_filters:
- attributeDefinitionId: -32767
enumValues: [3]
Common attribute IDs:
- Electrical Service (-32767): 0=None, 1=15A, 2=20A, 3=30A, 4=50A
- Service Type (-32768): 3=Standard, 5=Electric, 6=Elec+Water, 7=Full
|
Tested this branch against Parks Canada (rec area 14) and BC Parks (12) on camply 0.34.1 — the crash is fixed and availability works. 🎉
One thing to flag: across 12 different Parks Canada parks (Banff, Jasper, Forillon, Fundy, Grasslands, Kootenay, …) I got 0 availability with no errors. That's plausibly just peak-season-full (national parks book out months ahead), but I couldn't independently confirm a Parks-Canada availability hit, so I can't fully rule out a Net: big improvement — un-breaks the whole provider and availability is confirmed working (BC Parks). Thanks for the fix! 🙏 Repro: |
|
Update — I dug into the Parks Canada 0s from my earlier comment and can confirm: PC availability works, and this PR effectively resolves #291 too. My earlier zeros were just peak-season-full (Banff/Jasper book out months ahead). Testing an off-peak window (Sep–Nov) instead, Parks Canada returns real availability — e.g. Banff – Tunnel Mountain Village 2: 36 nights (first I traced the raw So: 👍 crash fixed, availability confirmed for both BC Parks and Parks Canada — looks like this closes #377, #405, and #291. |
|
I tested the fix in my side. I works well when there is no availability : But not when there are availabilities: |
|
Nice repro @bruno0o — that failure pattern (fine with 0 availability, 404 only when sites are available) points right at the culprit. Why it only breaks when there's availability
for site in sites: # only non-empty when availability exists
site_details = self.campsite_finder.get_site_details(
self._recreation_area_id, site.resource_id
)
Why the current fix doesn't fully land Two gaps:
Suggested approach I run this same GoingToCamp platform in production against WA State Parks, and I don't call def _stub_site(self, resource_id):
return {
"resourceId": resource_id,
"localizedValues": [{"name": f"Site {resource_id}"}],
"minCapacity": 1, "maxCapacity": 1,
"definedAttributes": [], "site_attributes": {},
}
def get_site_details(self, rec_area_id: int, resource_id: int):
# /api/resource/details was removed and 404s whenever a real site is looked up — which is why
# searches only fail when there IS availability. Availability itself comes from
# /api/availability/map, so treat details as optional enrichment and degrade gracefully.
if getattr(self, "_site_details_gone", False):
return self._stub_site(resource_id)
if not hasattr(self, "_attribute_details"):
try:
self._attribute_details = self._api_request(rec_area_id, "ATTRIBUTE_DETAILS")
except ConnectionError:
self._attribute_details = {}
attribute_details = self._attribute_details
try:
site_details = self._api_request(rec_area_id, "SITE_DETAILS", {"resourceId": resource_id})
except ConnectionError:
self._site_details_gone = True # dead endpoint — stop hammering it for every site
return self._stub_site(resource_id)
# ... existing definedAttributes parsing unchanged ...And I'd downgrade the log for a handled endpoint so it doesn't scream ERROR on every site — e.g. an optional That leaves searches fully working when availability exists (sites come back named |
Summary
rootMapIdinstead of MapId lookup (builds on PR Fix GoingToCamp provider KeyError and broken site details endpoint #391 by @aniketde)attribute_filterssupport for GoingToCamp provider to filter campsites by attributes like electrical serviceenumValuesformat and JSON encoding as required by the GoingToCamp APIChanges
going_to_camp_provider.py: Use rootMapId, add attribute_filters parameter to list_site_availability(), properly JSON-encode filterDatasearch_going_to_camp.py: Pass attribute_filters through to providersearch_model.py: Add attribute_filters field to YAML config modelyaml_utils.py: Pass attribute_filters from YAML to provider kwargsUsage
Via YAML config file:
Common attribute filters:
Test plan
🤖 Generated with Claude Code