db-vendo-client

repository·main·Indexed 41 days ago

https://github.com/public-transport/db-vendo-client

A client for bahn.de public transport APIs, designed as a drop-in replacement for hafas-client to access Deutsche Bahn "vendo" and "movas" APIs. Version 6.11.3 supports multiple profiles (db, dbnav, dbweb, dbris) for retrieving journeys, trip details, and station boards. It includes features for request throttling, automatic retries, and User-Agent randomization. Note that endpoints do not enable CORS, requiring a backend proxy or REST API wrapper for standard web browser environments.

Tokens
19.3K
Snippets
58
Records
74
Agent score
50%

What's inside db-vendo-client

  1. Understand the trip() response format

    main

    The trip() method returns an object containing trip details, including line information, current location, origin, destination, and stopovers.

    Key Timing Behavior: Following the Friendly Public Transport Format v2 draft spec, the returned departure and arrival times include the current delay. The departureDelay and arrivalDelay fields express the difference between the actual time and the scheduled time.

    Note on realtimeDataUpdatedAt: This field is currently returned but not populated in db-vendo-client because the upstream APIs do not provide it.

    {
    	id: '1|31431|28|86|17122017',
    	direction: 'S Spandau',
    	line: {
    		type: 'line',
    		id: '18299',
    		fahrtNr: '12345',
    		name: 'S9',
    		// ...
    	},
    	currentLocation: {
    		type: 'location',
    		latitude: 52.447455,
    		longitude: 13.522464,
    	},
    	origin: {
    		type: 'station',
    		id: '900000260005',
    		name: 'S Flughafen Berlin-Schönefeld',
    		// ...
    	},
    	departure: '2017-12-17T18:37:00+01:00',
    	plannedDeparture: '2017-12-17T18:37:00+01:00',
    	departureDelay: null,
    	// ...
    	destination: {
    		type: 'station',
    		id: '900000029101',
    		name: 'S Spandau',
    		// ...
    	},
    	arrival: '2017-12-17T19:50:30+01:00',
    	plannedArrival: '2017-12-17T19:49:00+01:00',
    	arrivalDelay: 90,
    	// ...
    	stopovers: [ /* … */ ]
    }
  2. Choose a DB API profile

    main

    The client supports multiple profiles, each wrapping different DB APIs with varying capabilities, stability, and quota limits. Choose the profile that best fits your requirements for features like tickets, polylines, or API key usage.

    Profiledbdbnavdbwebdbris
    API Key required?✅ No✅ No✅ No❌ Yes
    All endpoints supported?✅ Yes✅ Yes✅ Yes (except stop())⚠️ Only boards
    Board duration1h1h1hup to 12h
    RemarksImportant onlyImportant onlyAll remarksAll remarks
    TicketsrefreshJourney() onlyrefreshJourney() onlyrefreshJourney() only❌ No
    PolylinesrefreshJourney()/trip() onlyrefreshJourney()/trip() onlyrefreshJourney()/trip() only❌ No
    Trip IDsHAFASHAFASHAFASRIS
    StabilityLess stableMore stableLess stableMore stable
    Quotas60 req/min60 req/minAggressive blockingDepends on key
  3. Understand the `journeys` response format

    main

    The journeys() method resolves to an object containing:

    • journeys: An array of journey objects. Each journey contains legs (the individual segments of the trip).
    • earlierRef / laterRef: Tokens used for pagination.
    • realtimeDataUpdatedAt: Timestamp of the last realtime update (currently not set in db-vendo-client).

    Journey Leg Details

    Each leg includes:

    • tripId: Unique identifier for the trip.
    • line: Information about the transport line (type, name, operator, etc.).
    • origin / destination: Station details.
    • departure / arrival: ISO strings including current delay.
    • plannedDeparture / plannedArrival: Scheduled times.
    • departureDelay / arrivalDelay: Difference between scheduled and actual time in seconds.
    • remarks: Hints or warnings (e.g., barrier-free).

    Note: If a leg is cancelled, cancelled: true is added, and time/platform fields will be null.

  4. Use `bmisNumber` for business customer rates

    main

    Business customers can access corporate rates using a 7-digit BMIS number. There are two ways to provide this:

    1. Directly in the journeys call: Pass bmisNumber in the options object.
    2. Using createBusinessClient: Create a specialized client where the BMIS number is automatically included in every request.
    // Option 1: Direct parameter
    await client.journeys(from, to, {
    	bmisNumber: '1234567'
    })
    
    // Option 2: Specialized client
    import {createBusinessClient} from 'db-vendo-client'
    import {profile as dbProfile} from 'db-vendo-client/p/db/index.js'
    
    const businessClient = createBusinessClient(dbProfile, userAgent, '1234567')
    await businessClient.journeys(from, to)
  5. Randomize the User-Agent header

    main

    By default, db-vendo-client sends the userAgent string passed to createClient exactly as provided in the User-Agent HTTP header. To enable randomization of the client name, set randomizeUserAgent: true within the profile object passed to createClient.

    const client = createClient({
    	...someProfile,
    	randomizeUserAgent: true,
    }, userAgent)
  6. How to intercept DB Navigator traffic

    main

    To obtain API dumps from the DB Navigator app, you must modify the Android application to allow user-installed Certificate Authorities (CAs) for SSL/TLS interception. This process involves decompiling the APK, modifying the network security configuration, and reinstalling the modified app on an Android device.

    Steps to intercept traffic:

    1. Download or extract the Split APK.
    2. Merge the APK (e.g., using APKEditor).
    3. Decompile the merged APK using apktool.
    4. Edit res/xml/network_security_config.xml to allow user CAs (not just in debug mode).
    5. Recompile the APK using apktool and sign it.
    6. Install the signed APK on an Android device.
    7. Intercept traffic using a MITM (Man-in-the-Middle) decryption tool. For example, use PCAPdroid with the mitm addon, which does not require root, by installing the CA certificate into the Android system store.
  7. Log requests and responses

    main

    You can intercept and process raw Fetch Request and Response objects by providing logRequest and logResponse functions in the profile object passed to createClient.

    • logRequest(ctx, fetchRequest, requestId): ctx contains the profile and options; fetchRequest is the Request object.
    • logResponse(ctx, fetchResponse, body, requestId): fetchResponse is the Response object; body is the response body.
    import {createClient} from 'db-vendo-client'
    import {profile as dbProfile} from 'db-vendo-client/p/db/index.js'
    
    const userAgent = 'link-to-your-project-or-email'
    
    const logRequest = (ctx, fetchRequest, requestId) => {
    	const {dbProfile, opt} = ctx
    	console.debug(requestId, fetchRequest.headers, fetchRequest.body + '')
    }
    
    const logResponse = (ctx, fetchResponse, body, requestId) => {
    	console.debug(requestId, fetchResponse.headers, body + '')
    }
    
    const client = createClient({
    	...dbProfile,
    	logRequest,
    	logResponse,
    }, userAgent)
  8. Implement caching for db-vendo-client

    main

    Because the DB APIs are subject to aggressive blocking and quotas, it is highly recommended to implement caching. You can do this in two ways:

    1. HTTP Proxy Cache: Place a cache (e.g., Nginx) in front of your REST API server.
    2. Client-side Caching: Use cached-hafas-client and drop in db-vendo-client as the underlying client instance.
  9. Run automated tests in `db-vendo-client`

    main

    The project uses three distinct types of automated tests to ensure compatibility with dynamic HAFAS endpoints:

    • Unit tests: Test individual logic components (e.g., date/time parsing) in isolation. Run via npm run test-unit.
    • End-to-end (E2E) tests: Execute actual HTTP requests against live HAFAS endpoints for specific profiles. Run via npm run test-e2e.
    • Integration tests: Run E2E tests against pre-recorded HTTP request fixtures to ensure determinism. Run via npm run test-integration.

    To ensure reproducibility, tests query transit data for a fixed point in the future, which is hard-coded in each profile's test suite (located in test/e2e/*.js).

    npm run test-unit
    npm run test-e2e
    npm run test-integration
  10. Manage integration test fixtures with VCR_MODE

    main

    Integration tests use a recording/mocking mechanism controlled by the $VCR_MODE environment variable. This allows you to capture real API responses as fixtures or play them back during testing.

    • VCR_MODE=record: Records actual HTTP requests made during the test. The tests will query data for the specific date/time defined by T_MOCK in the test file.
    • VCR_MODE=playback: Uses the recorded fixtures in test/e2e/fixtures to mock HTTP responses, making tests deterministic and independent of live API availability.
    # To record new fixtures
    VCR_MODE=record npm run test-integration
    
    # To run tests using existing fixtures
    VCR_MODE=playback npm run test-integration