db-vendo-client/docs/writing-a-profile.md
2018-03-15 01:10:52 +01:00

5.9 KiB
Raw Blame History

Writing a profile

Per endpoint, there is an endpoint-specific customisation called profile which may for example do the following:

  • handle the additional requirements of the endpoint (e.g. authentication),
  • extract additional information from the data provided by the endpoint,
  • guard against triggering bugs of certain endpoints (e.g. time limits).

This guide is about writing such a profile. If you just want to use an already supported endpoint, refer to the API documentation instead.

Note: If you get stuck, ask for help by creating an issue! We're motivated to help people expand the scope of this library.

0. How does the profiles work?

A profile contains of three things:

  • mandatory details about the HAFAS endpoint
    • endpoint: The protocol, host and path of the endpoint.
    • locale: The BCP 47 locale of your endpoint (or the area that your endpoint covers).
    • timezone: An IANA-time-zone-compatible timezone of your endpoint.
  • flags indicating that features are supported by the endpoint e.g. journeyRef
  • methods overriding the default profile

As an example, let's say that our endpoint https://example.org/bin/mgate.exe has the timezone Europe/Vienna and locale de-AT. It also returns all lines names prefixed with foo . We can strip them like this:

// get the default line parser
const createParseLine = require('hafas-client/parse/line')

const createParseLineWithoutFoo = (profile, operators) => {
	const parseLine = createParseLine(profile, operators)

	// wrapper function with additional logic
	const parseLineWithoutFoo = (l) => {
		const line = parseLine(l)
		line.name = line.name.replace(/foo /g, '')
		return line
	}
	return parseLineWithoutFoo
}

Our profile will look like this:

const myProfile = {
	endpoint: 'https://example.org/bin/mgate.exe',
	parseLine: createParseLineWithoutFoo
}

If you pass this profile into hafas-client, the parseLine method will override the default one.

1. Setup

Note: There are many ways to find the required values. This way is rather easy and has worked for most of the apps that I've looked at so far.

  1. Get an iOS or Android device and download the "official" app for the public transport provider that you want to build a profile for.
  2. Configure a man-in-the-middle HTTP proxy like mitmproxy.
    • Note: This method does not work if the app uses public key pinning. In this case (the app won't be able to query data), please create an issue, so we can discuss other techniques.
  3. Record requests of the app.
    • To help others in the future, post the requests (in their entirety!) on GitHub, e.g. in as format like this. This will also let us help you if you have any questions.
    • Make sure to cover all relevant sections of the app, e.g. "journeys", "departures", "live map". Better record more than less; You will regret not having enough information later on.

2. Basic profile

  • Identify the endpoint. The protocol, host and path of the endpoint, but not the query string.
    • Note: hafas-client for now only supports the interface providing JSON (generated from XML), which is being used by the corresponding iOS/Android apps. It supports neither the JSONP, nor the XML, nor the HTML interface. If the endpoint does not end in mgate.exe, it mostly likely won't work.
  • Identify the locale. Basically guess work; Use the date & time formats as an indicator.
  • Identify the timezone. This may be tricky, a for example Deutsche Bahn returns departures for Moscow as +01:00 instead of +03:00.
  • Copy the authentication and other meta fields, namely ver, ext, client and lang.
    • You can find these fields in the root of each request JSON. Check a VBB request and the corresponding the VBB profile for an example.
    • Add a function transformReqBody(body) to your profile, which assigns them to body.

If you want, you can now verify that the profile works; I've prepared a script for that. Alternatively, submit Pull Request and I will help you out with testing and improvements.

3. Additional info

We consider these improvements to be optional:

  • Check if the endpoint supports the journey legs call.
    • In the app, check if you can query details for the status of a single journey leg. It should load realtime delays and the current progress.
    • If this feature is supported, add journeyLeg: true to the profile.
  • Check if the endpoint supports the live map call. Does the app have a "live map" showing all vehicles within an area? If so, add radar: true to the profile.
  • Consider transforming station & line names into the formats that's most suitable for local users. Some examples:
    • M13 (Tram) -> M13. With Berlin context, it is obvious that M13 is a tram.
    • Berlin Jungfernheide Bhf -> Berlin Jungfernheide. With local context, it's obvious that Jungfernheide is a train station.
  • Check if the endpoint has non-obvious limitations and let use know about these. Examples:
    • Some endpoints have a time limit, after which they won't return more departures, but silently discard them.