calculateRoute method
Calculate a route for the given request.
Implementation
@override
Future<RouteResult> calculateRoute(RouteRequest request) async {
final stopwatch = Stopwatch()..start();
final requestBody = jsonEncode({
'locations': [
{'lat': request.origin.latitude, 'lon': request.origin.longitude},
{
'lat': request.destination.latitude,
'lon': request.destination.longitude,
},
],
'costing': request.costing,
'directions_options': {
'language': request.language,
'units': 'kilometers',
},
'costing_options': {
request.costing: {'use_highways': 0.8, 'use_tolls': 0.5},
},
});
final uri = Uri.parse('$baseUrl/route');
try {
final response = await _client
.post(
uri,
headers: {'Content-Type': 'application/json'},
body: requestBody,
)
.timeout(routeTimeout);
stopwatch.stop();
// Decode bytes as UTF-8 explicitly: response.body honors the
// content-type charset header and falls back to Latin-1 when a server
// omits it. Valhalla returns fully-localized instruction text (e.g.
// Japanese via directions_options.language), so a charset-less server
// would mojibake the whole narration — a larger exposure than OSRM's
// street names.
final bodyText = utf8.decode(response.bodyBytes);
if (response.statusCode != 200) {
final errorBody = _tryParseJson(bodyText);
final errorMsg = errorBody?['error'] ?? bodyText;
throw RoutingException(
'Valhalla route failed (${response.statusCode}): $errorMsg',
);
}
final json = jsonDecode(bodyText) as Map<String, dynamic>;
return _parseRouteResponse(json, stopwatch.elapsed);
} on RoutingException {
rethrow;
} on Exception catch (e) {
throw RoutingException('Valhalla network error: $e');
}
}