From 71776ee8f0df0bf6e3709bc2c6abee91f1ad14c6 Mon Sep 17 00:00:00 2001 From: Doug Borg Date: Sun, 8 Feb 2026 10:07:25 -0700 Subject: [PATCH] Fix route calculation HTTP 400 by filtering empty profile tags Built-in profiles (Flock, Motorola, etc.) include placeholder empty values like camera:mount: '' for user refinement. When these get serialized into the routing request body, the alprwatch API rejects them with HTTP 400. Fix: strip empty-valued tags from enabled_profiles before sending the routing request. Also refactor RoutingService to accept an injectable http.Client for testability, and log error response bodies for easier debugging of future API issues. Co-Authored-By: Claude Opus 4.6 --- lib/services/routing_service.dart | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/services/routing_service.dart b/lib/services/routing_service.dart index b2dc90f..3fa6f82 100644 --- a/lib/services/routing_service.dart +++ b/lib/services/routing_service.dart @@ -27,6 +27,9 @@ class RouteResult { class RoutingService { static const String _baseUrl = 'https://alprwatch.org/api/v1/deflock/directions'; static const String _userAgent = 'DeFlock/1.0 (OSM surveillance mapping app)'; + final http.Client _client; + + RoutingService({http.Client? client}) : _client = client ?? http.Client(); // Calculate route between two points using alprwatch Future calculateRoute({ @@ -40,10 +43,12 @@ class RoutingService { final enabledProfiles = AppState.instance.enabledProfiles.map((p) { final full = p.toJson(); + final tags = Map.from(full['tags'] as Map); + tags.removeWhere((key, value) => value.isEmpty); return { 'id': full['id'], 'name': full['name'], - 'tags': full['tags'], + 'tags': tags, }; }).toList(); @@ -65,7 +70,7 @@ class RoutingService { debugPrint('[RoutingService] alprwatch request: $uri $params'); try { - final response = await http.post( + final response = await _client.post( uri, headers: { 'User-Agent': _userAgent, @@ -75,6 +80,7 @@ class RoutingService { ).timeout(kNavigationRoutingTimeout); if (response.statusCode != 200) { + debugPrint('[RoutingService] Error response body: ${response.body}'); throw RoutingException('HTTP ${response.statusCode}: ${response.reasonPhrase}'); }