spider_sdk 0.1.0
spider_sdk: ^0.1.0 copied to clipboard
Native Dart SDK for the Spider transit API — trip planning, stop search, and live realtime data.
spider_sdk (Dart / Flutter) #
The Dart SDK for the Spider transit API — trip planning, stop search, and live realtime data behind one typed client. It ships the exact query documents the gateway allows and attaches auth for you, so you get a typed, closed surface out of the box.
A native Dart package (single dependency: package:http), usable from Flutter (iOS/Android/web/desktop) and
plain Dart. It is a sibling of the Kotlin, TypeScript, and Swift SDKs and mirrors their domain model and
semantics, adapted to Dart idioms (Future, Stream, sealed classes).
Install #
dependencies:
spider_sdk: ^0.1.0
Quickstart #
Construct a client with your environment's base URL and API key, then call a surface. Every call returns a
SpiderResult<T> you branch on before reading the value.
import 'package:spider_sdk/spider_sdk.dart';
final client = SpiderClient('https://your-env-slug.api.tiducto.eu', apiKey);
final result = await client.routing.plan(const PlanOptions(
origin: Location.coordinate(49.1908, 16.6128),
destination: Location.coordinate(49.2270, 16.5273),
first: 3,
));
switch (result) {
case Success(:final value):
for (final edge in value.edges) {
final legs = edge.itinerary.legs.map((l) => l.mode?.name ?? 'walk').join(' → ');
print('${edge.itinerary.durationSeconds ~/ 60} min: $legs');
}
case Failure(:final error):
print('plan failed: ${error.code.name} — ${error.message}');
}
Trip planning #
final result = await client.routing.plan(PlanOptions(
origin: const Location.stop('U123Z1'),
destination: const Location.coordinate(49.19, 16.61),
departAt: DateTime.now(),
allowedTransitModes: const [TransitMode.tram, TransitMode.bus, TransitMode.subway],
maxTransfers: 2,
searchWindowMinutes: 90,
wheelchairAccessible: true,
));
// Page forward / backward.
if (result case Success(:final value)) {
final next = await client.routing.planNext(value); // null if no next page
}
// Or stream itineraries, stepping the search window until you have enough.
await for (final page in client.routing.planUntil(
const PlanOptions(origin: Location.stop('A'), destination: Location.stop('B')),
targetResults: 20,
)) {
if (page case Success(:final value)) { /* collect value.edges */ }
}
Departures & a single trip #
final departures = await client.routing.departures('U123Z1', numberOfDepartures: 10);
final trip = await client.routing.trip('T-4821', serviceDate: '2026-08-21');
Stop search #
// Free text, narrowed by administrative area.
final stops = await client.stops.search(const StopFilter(name: 'Náměstí', city: 'Example City'));
// Nearest stops within 500 m, closest first.
final nearby = await client.stops.near(49.19, 16.61, radiusMeters: 500);
// Stops inside a bounding box (SW corner, then NE corner).
final inBox = await client.stops.within(49.18, 16.59, 49.21, 16.63);
// A single stop by GTFS id — Success carries the stop, or null when none matches.
final one = await client.stops.byId('U123Z1');
Realtime (poll-based) #
// One-shot.
final positions = await client.realtime.vehicles(['T-1', 'T-2']);
final alerts = await client.realtime.alerts();
// Or a change-detecting stream (yields only when the data changes; cancel the subscription to stop).
final sub = client.realtime.pollVehicles(['T-1', 'T-2'], intervalMs: 10000).listen((update) {
if (update case Success(:final value)) { /* update the map */ }
});
// later: await sub.cancel();
Errors #
Ordinary failures are values, not thrown: every call returns SpiderResult<T> (Success / Failure), and
Failure carries a SpiderError with a stable code (network, timeout, unauthorized, notFound,
server, rateLimited, decoding, unknown). The one thrown error is SpiderContractMismatchError —
raised when the gateway speaks a different major contract version than this SDK.
Options #
final client = SpiderClient(base, key, SpiderClientOptions(
timeout: const Duration(seconds: 20), // default 30s
routing: const FeatureOptions(autoRetry: AutoRetryOptions(maxAttempts: 3)), // opt-in retries, per surface
));
Retries (opt-in per surface) back off on 429/5xx and network/timeout errors, honoring a numeric
Retry-After. Inject a custom SpiderHttpClient via SpiderClientOptions(httpClient:) for tests or proxies.
Contract & codegen #
The wire models under lib/src/contract/ and the persisted-query ids are generated from the published
contract by scripts/generate-contract.sh (via tiducto/spider-codegen) and committed — the package carries
the types, not the spec. client.contractVersion reports the contract version this SDK speaks (0.1). Do not
hand-edit generated files; re-run the script.