Subscriptions
In catering to the high expectations of modern booking flows, loading times can have dire effects on conversion rates. When latency is unavoidable, the next best thing is to provide an as rich experience as possible during the loading times, with the data available at any given time.
Streaming Data
With the All Aboard API, all the queries and mutations can be carried out over HTTPS
(GET
or POST
requests or over WebSockets). Some important queries are also available as a GraphQL subscription.
When interacting with the underlying train carrier APIs, some requests can unfortunately be very slow to finalise (up to 30+ seconds). The All Aboard API is structured in such a way to alleviate long loading times to the greatest extent possible. A key to better user experience is to repond with data as soon as it's made available — allowing you to process and present content while progressively fetching departures and fares.
To avoid request timeouts, it is recommended to perform certain queries
and mutations
over WebSockets, or subscription
where applicable. More on this below.
By subscribing to getJourneyOffer
, fares will be streamed in as they are produced, allowing you to progressively update a user interface as more fares are made available. The subscription will complete once all train segments and stopovers have resolved.
Good use of WebSockets
The primary benefit of using WebSockets is to stream data to the client, but they can also be used to avoid request timeouts. Some API calls may be more susceptible to timeouts than others. The following calls are recommended to be performed over WebSockets:
Example
This example illustrates how to initiate a subscription from a JavaScript environment (e.g. Web Browser) and log the response as it is streamed to the client.
js
import { createClient } from 'graphql-ws'
const client = createClient({
url: 'wss://api-gateway.allaboard.eu',
connectionParams: {
Authorization: 'Bearer AGENT_API_KEY'
}
})
const query = `
subscription GetJourneyOffer(
$journey: ID!
$passengers: [PassengerPlaceholderInput!]!
) {
getJourneyOffer(journey: $journey, passengers: $passengers) {
status
itinerary {
__typename
... on SegmentCollection {
status
segments {
departureAt
origin {
name
countryCode
}
}
fares {
name
price {
amount
currency
}
}
}
... on Stopover {
location {
name
countryCode
}
}
}
}
}
`
const variables = {
journey: '2f7cbe3a-5cd2-4a8f-9b38-31d0de662482',
passengers: [{ type: 'ADULT' }]
}
const subscription = client.iterate({ query, variables })
for await (const data of subscription) {
console.log(data)
}
import { createClient } from 'graphql-ws'
const client = createClient({
url: 'wss://api-gateway.allaboard.eu',
connectionParams: {
Authorization: 'Bearer AGENT_API_KEY'
}
})
const query = `
subscription GetJourneyOffer(
$journey: ID!
$passengers: [PassengerPlaceholderInput!]!
) {
getJourneyOffer(journey: $journey, passengers: $passengers) {
status
itinerary {
__typename
... on SegmentCollection {
status
segments {
departureAt
origin {
name
countryCode
}
}
fares {
name
price {
amount
currency
}
}
}
... on Stopover {
location {
name
countryCode
}
}
}
}
}
`
const variables = {
journey: '2b221c73-d43f-4430-82e0-e11066d58576',
passengers: [{ type: 'ADULT' }]
}
const subscription = client.iterate({ query, variables })
for await (const data of subscription) {
console.log(data)
}
json
{
"status": "LOADING",
"itinerary": [
{
"__typename": "SegmentCollection",
"status": "LOADING",
"segments": [
{
"departureAt": "2023-08-01T09:42:00",
"origin": {
"name": "Amsterdam",
"countryCode": "NL"
}
}
]
},
{
"__typename": "Stopover",
"location": {
"name": "Lyon",
"countryCode": "FR"
}
},
{
"__typename": "SegmentCollection",
"status": "LOADING",
"segments": [
{
"departureAt": "2023-08-02T08:00:00",
"origin": {
"name": "Lyon",
"countryCode": "FR"
}
}
]
}
]
}
{
"status": "LOADING",
"itinerary": [
{
"__typename": "SegmentCollection",
"status": "LOADING",
"segments": [
{
"departureAt": "2023-08-01T09:42:00",
"origin": {
"name": "Amsterdam",
"countryCode": "NL"
}
}
]
},
{
"__typename": "Stopover",
"location": {
"name": "Lyon",
"countryCode": "FR"
}
},
{
"__typename": "SegmentCollection",
"status": "LOADING",
"segments": [
{
"departureAt": "2023-08-02T08:00:00",
"origin": {
"name": "Lyon",
"countryCode": "FR"
}
}
]
}
]
}
json
{
"status": "LOADING",
"itinerary": [
{
"__typename": "SegmentCollection",
"status": "SUCCESS",
"segments": [
{
"departureAt": "2023-08-01T09:42:00",
"origin": {
"name": "Brussels",
"countryCode": "BE"
}
}
],
"fares": [
{
"name": "Second Class",
"price": {
"amount": 13400,
"currency": "EUR"
}
},
{
"name": "Premium",
"price": {
"amount": 19200,
"currency": "EUR"
}
}
]
},
{
"__typename": "Stopover",
"location": {
"name": "Lyon",
"countryCode": "FR"
}
},
{
"__typename": "SegmentCollection",
"status": "LOADING",
"segments": [
{
"departureAt": "2023-08-02T08:00:00",
"origin": {
"name": "Lyon",
"countryCode": "FR"
}
}
]
}
]
}
{
"status": "LOADING",
"itinerary": [
{
"__typename": "SegmentCollection",
"status": "SUCCESS",
"segments": [
{
"departureAt": "2023-08-01T09:42:00",
"origin": {
"name": "Brussels",
"countryCode": "BE"
}
}
],
"fares": [
{
"name": "Second Class",
"price": {
"amount": 13400,
"currency": "EUR"
}
},
{
"name": "Premium",
"price": {
"amount": 19200,
"currency": "EUR"
}
}
]
},
{
"__typename": "Stopover",
"location": {
"name": "Lyon",
"countryCode": "FR"
}
},
{
"__typename": "SegmentCollection",
"status": "LOADING",
"segments": [
{
"departureAt": "2023-08-02T08:00:00",
"origin": {
"name": "Lyon",
"countryCode": "FR"
}
}
]
}
]
}
json
{
"status": "SUCCESS",
"itinerary": [
{
"__typename": "SegmentCollection",
"status": "SUCCESS",
"segments": [
{
"departureAt": "2023-08-01T09:42:00",
"origin": {
"name": "Brussels",
"countryCode": "BE"
}
}
],
"fares": [
{
"name": "Second Class",
"price": {
"amount": 13400,
"currency": "EUR"
}
},
{
"name": "Premium",
"price": {
"amount": 19200,
"currency": "EUR"
}
}
]
},
{
"__typename": "Stopover",
"location": {
"name": "Lyon",
"countryCode": "FR"
}
},
{
"__typename": "SegmentCollection",
"status": "SUCCESS",
"segments": [
{
"departureAt": "2023-08-02T08:00:00",
"origin": {
"name": "Lyon",
"countryCode": "FR"
}
}
],
"fares": [
{
"name": "Second Class – Fully refundable",
"price": {
"amount": 14900,
"currency": "EUR"
}
},
{
"name": "Comfort Class – Fully refundable",
"price": {
"amount": 17200,
"currency": "EUR"
}
}
]
}
]
}
{
"status": "SUCCESS",
"itinerary": [
{
"__typename": "SegmentCollection",
"status": "SUCCESS",
"segments": [
{
"departureAt": "2023-08-01T09:42:00",
"origin": {
"name": "Brussels",
"countryCode": "BE"
}
}
],
"fares": [
{
"name": "Second Class",
"price": {
"amount": 13400,
"currency": "EUR"
}
},
{
"name": "Premium",
"price": {
"amount": 19200,
"currency": "EUR"
}
}
]
},
{
"__typename": "Stopover",
"location": {
"name": "Lyon",
"countryCode": "FR"
}
},
{
"__typename": "SegmentCollection",
"status": "SUCCESS",
"segments": [
{
"departureAt": "2023-08-02T08:00:00",
"origin": {
"name": "Lyon",
"countryCode": "FR"
}
}
],
"fares": [
{
"name": "Second Class – Fully refundable",
"price": {
"amount": 14900,
"currency": "EUR"
}
},
{
"name": "Comfort Class – Fully refundable",
"price": {
"amount": 17200,
"currency": "EUR"
}
}
]
}
]
}