Skip to content

Commit e6e153c

Browse files
authored
Merge pull request #15 from openTdataCH/feature/ojp-request-trr
Adds OJP2.0 TRR request
2 parents c1fdd19 + 9fbedd4 commit e6e153c

9 files changed

Lines changed: 144 additions & 11 deletions

File tree

‎README.md‎

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,45 @@ $ ng serve
3030
- [./src/app/config/api-tokens.ts](./src/app/config/api-tokens.ts)
3131
- duplicate and edit one of the existing OpenAPI specs - [./public/openapi](./public/openapi)
3232

33+
## Placeholders
34+
35+
- the OpenAPI specs in [./public/openapi](./public/openapi) contain placeholders that are dynamically replaced at render time
36+
- the registry of placeholders is defined in [./src/app/detail/detail.ts](./src/app/detail/detail.ts)
37+
38+
```
39+
const handlerLoaders: Record<PlaceHolderKey, () => Promise<PlaceholderModule>> = {
40+
today: () => import('./placeholders/today'),
41+
isoTimestamp: () => import('./placeholders/iso-timestamp'),
42+
RESPONSE_XML_LIR1: () => import('./placeholders/ojp-lir1'),
43+
RESPONSE_XML_TR1: () => import('./placeholders/ojp-tr1'),
44+
REQUEST_XML_FR1: () => import('./placeholders/ojp-fr1'),
45+
RESPONSE_XML_FR2: () => import('./placeholders/ojp-fr2'),
46+
REQUEST_XML_TRR1: () => import('./placeholders/ojp-trr1'),
47+
};
48+
```
49+
50+
- example of placeholder usage
51+
52+
```
53+
<OJPTripInfoRequest>
54+
<siri:RequestTimestamp>{{isoTimestamp}}</siri:RequestTimestamp>
55+
<siri:MessageIdentifier>TIR-1a</siri:MessageIdentifier>
56+
<JourneyRef>ch:1:sjyid:100001:18355-001</JourneyRef>
57+
<OperatingDayRef>{{today}}</OperatingDayRef>
58+
</OJPTripInfoRequest>
59+
```
60+
61+
`{{today}}` string is replaced with content resolved in [./src/app/detail/placeholders/today.ts](./src/app/detail/placeholders/today.ts)
62+
63+
```
64+
summary: "11. Trip Refine Request"
65+
description: "TRR request for the first trip of Bern - Zurich TR request occuring next day after 10AM. The TR response XML is pre-fetched using ojp-sdk"
66+
value: |
67+
{{REQUEST_XML_TRR1}}
68+
```
69+
70+
`{{REQUEST_XML_TRR1}}` string is replaced with `ojp-sdk` TripRequest parsed in [./src/app/detail/placeholders/ojp-trr1.ts](./src/app/detail/placeholders/ojp-trr1.ts)
71+
3372
## Deployment
3473

3574
A GitHub Actions workflow (under [.github/workflows/deploy-pages.yml](./.github/workflows/deploy-pages.yml)) builds the site and publishes it to GitHub Pages on push to the default branch

‎public/openapi/ojp2.0/openapi.template.yaml‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,11 @@ paths:
357357
</siri:ServiceRequest>
358358
</OJPRequest>
359359
</OJP>
360+
exampleTRR1:
361+
summary: "11. Trip Refine Request"
362+
description: "TRR request for the first trip of Bern - Zurich TR request occuring next day after 10AM. The TR response XML is pre-fetched using ojp-sdk"
363+
value: |
364+
{{REQUEST_XML_TRR1}}
360365
responses:
361366
"200":
362367
description: "Successful response"

‎src/app/detail/detail.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,15 @@ export type PlaceHolderKey =
2626
| 'today'
2727
| 'isoTimestamp'
2828
| 'RESPONSE_XML_LIR1'
29-
| 'RESPONSE_XML_TR1';
29+
| 'RESPONSE_XML_TR1'
30+
| 'REQUEST_XML_TRR1';
3031

3132
const handlerLoaders: Record<PlaceHolderKey, () => Promise<PlaceholderModule>> = {
3233
today: () => import('./placeholders/today'),
3334
isoTimestamp: () => import('./placeholders/iso-timestamp'),
3435
RESPONSE_XML_LIR1: () => import('./placeholders/ojp-lir1'),
3536
RESPONSE_XML_TR1: () => import('./placeholders/ojp-tr1'),
37+
REQUEST_XML_TRR1: () => import('./placeholders/ojp-trr1'),
3638
};
3739

3840
@Component({

‎src/app/detail/placeholders/ojp-lir1.ts‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import * as OJP from 'ojp-sdk';
2-
31
import { PlaceholderContext, PlaceholderHandler } from './placeholder';
42
import { OJP_PlaceholderHandler } from './ojp';
53

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import * as OJP from 'ojp-sdk';
2+
3+
import { OJP_PlaceholderHandler } from './ojp';
4+
5+
export default abstract class OJP_TR_Shared_PlaceholderHandle extends OJP_PlaceholderHandler {
6+
protected async fetchTripRequest(sdk: OJP.AnySDK): Promise<OJP.TripRequestResponse | OJP.OJPv1_TripRequestResponse> {
7+
const fromStopRef = '8507000';
8+
const toStopRef = '8503000';
9+
10+
const request = sdk.requests.TripRequest.initWithPlaceRefsOrCoords(fromStopRef, toStopRef);
11+
12+
// set date to 10:00 next day
13+
const date = new Date();
14+
date.setHours(10, 0, 0, 0);
15+
date.setDate(date.getDate() + 1);
16+
request.setDepartureDatetime(date);
17+
18+
// TODO: cache requests so we can re-use them
19+
const response = await request.fetchResponse(sdk);
20+
21+
return response;
22+
}
23+
}

‎src/app/detail/placeholders/ojp-tr1.ts‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import * as OJP from 'ojp-sdk';
2-
31
import { PlaceholderContext, PlaceholderHandler } from './placeholder';
42
import { OJP_PlaceholderHandler } from './ojp';
53

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import * as OJP from 'ojp-sdk';
2+
import * as OJP_Types from 'ojp-shared-types';
3+
4+
import { PlaceholderContext, PlaceholderHandler } from './placeholder';
5+
import { AppHelpers } from '../../helpers/app.helpers';
6+
import OJP_TR_Shared_PlaceholderHandle from './ojp-tr-shared';
7+
8+
export default class OJP_TRR_1_PlaceholderHandle extends OJP_TR_Shared_PlaceholderHandle implements PlaceholderHandler {
9+
private async buildRequest(sdk: OJP.SDK<'2.0'>): Promise<OJP.TripRefineRequest> {
10+
const trResponse = await this.fetchTripRequest(sdk) as OJP.TripRequestResponse;
11+
12+
if (!trResponse.ok) {
13+
throw new Error('<Error>Invalid TR XML response</Error>');
14+
}
15+
16+
if (trResponse.value.tripResult.length === 0) {
17+
throw new Error('<Error>No trips found for TR XML response</Error>');
18+
}
19+
20+
const trips = trResponse.value.tripResult.map(el => el.trip);
21+
const firstTrip = trips[0];
22+
23+
// HACK - remove expectedDepartureOccupancy nodes due to backend issue
24+
// - see https://github.com/openTdataCH/ojp-sdk/issues/387
25+
firstTrip.leg.forEach(leg => {
26+
if (leg.timedLeg) {
27+
const timedLeg = leg.timedLeg as OJP_Types.TimedLegSchema;
28+
timedLeg.legBoard.expectedDepartureOccupancy = [];
29+
timedLeg.legAlight.expectedDepartureOccupancy = [];
30+
timedLeg.legIntermediate.forEach(legIntermediate => {
31+
legIntermediate.expectedDepartureOccupancy = [];
32+
})
33+
}
34+
});
35+
36+
const trrRequest = OJP.TripRefineRequest.initWithTrip(firstTrip);
37+
38+
return trrRequest;
39+
}
40+
41+
public async resolve(context: PlaceholderContext): Promise<string | string[]> {
42+
const sdk = this.buildSDK(context) as OJP.SDK<'2.0'>;
43+
44+
let trrRequest: OJP.TripRefineRequest | null = null;
45+
try {
46+
trrRequest = await this.buildRequest(sdk);
47+
} catch (e) {
48+
return '<Error>Invalid XML response</Error>';
49+
}
50+
51+
const xmlConfig = OJP.DefaultXML_Config;
52+
const requestXML = trrRequest.buildRequestXML('de', this.requestorRef, xmlConfig);
53+
const responseXML_F = AppHelpers.prettyPrintXML(requestXML);
54+
const responseXML_Lines = responseXML_F.split('\n');
55+
56+
return responseXML_Lines;
57+
}
58+
}

‎src/app/detail/placeholders/ojp.ts‎

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
import * as OJP from 'ojp-sdk';
22

3-
import { PlaceholderContext, PlaceholderHandler } from './placeholder';
3+
import { PlaceholderContext } from './placeholder';
44
import { API_Tokens } from '../../config/api-tokens';
55
import { AppHelpers } from '../../helpers/app.helpers';
66

77
type OJP_AnyRequest = OJP.LocationInformationRequest | OJP.OJPv1_LocationInformationRequest
88
| OJP.TripRequest | OJP.OJPv1_TripRequest;
99

1010
export abstract class OJP_PlaceholderHandler {
11-
protected buildSDK(context: PlaceholderContext): OJP.AnySDK {
11+
protected requestorRef: string;
12+
13+
constructor() {
14+
this.requestorRef = 'odmch-api-explorer';
15+
}
16+
17+
protected buildSDK(context: PlaceholderContext, useOJPv1: boolean = false): OJP.AnySDK {
1218
let apiURL: string | null = null;
1319
let ojpVersion: OJP.OJP_VERSION = '2.0';
1420
try {
@@ -23,6 +29,10 @@ export abstract class OJP_PlaceholderHandler {
2329
if (operationId.toLowerCase().startsWith('ojp1.0')) {
2430
ojpVersion = '1.0';
2531
}
32+
33+
if (useOJPv1) {
34+
ojpVersion = '1.0';
35+
}
2636
} catch {
2737
throw new Error('Cant find apiURL in YAML spec');
2838
}
@@ -36,19 +46,19 @@ export abstract class OJP_PlaceholderHandler {
3646
};
3747
const sdk: OJP.AnySDK = (() => {
3848
if (ojpVersion === '1.0') {
39-
const legacySDK = OJP.SDK.v1('odmch-api-explorer', stageConfig, 'de');
49+
const legacySDK = OJP.SDK.v1(this.requestorRef, stageConfig, 'de');
4050
return legacySDK;
4151
}
4252

43-
const defaultSDK = OJP.SDK.create('odmch-api-explorer', stageConfig, 'de');
53+
const defaultSDK = OJP.SDK.create(this.requestorRef, stageConfig, 'de');
4454
return defaultSDK;
4555
})();
4656

4757
return sdk;
4858
}
4959

5060
protected async fetchResponse(sdk: OJP.AnySDK, request: OJP_AnyRequest) {
51-
try {
61+
try {
5262
await request.fetchResponse(sdk);
5363
} catch (e) {
5464
return '<Error>Invalid XML response</Error>';

‎src/app/shared/footer/footer.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export class Footer {
1515

1616
public constructor() {
1717
this.model = {
18-
updateDateF: '15.Apr 2026'
18+
updateDateF: '20.Apr 2026'
1919
};
2020
}
2121
}

0 commit comments

Comments
 (0)