Rejseplanen

I denne øvelse skal vi arbejde med Rejseplanens API. Rejseplanen har lavet deres system sådan, at nysgerrige udefra der gerne vil eksperimentere med deres data, kan anmode om at få udleveret en såkaldt base-url. Med den kan man lave kald direkte ind i api’ets søgefunktionalitet, og dermed skabe nogle anderledes bud på, hvordan en rejse-app kunne udformes.

Vi begynder med at sætte en grundlæggende skabelon op, hvor man kan lave en enkel søgning på en rejse mellem to destinationer. Derefter skal i gruppevis lave noget interaktionsdesign og sætte nogle mål op, for hvad jeres egen app skal kunne.

Hent skabelonen her før du begynder

Læsestof

Eloquent Javascript: HTTP (til og med HTTP and Security). Her får du en god introduktion til hvad HTTP egentlig er for en arkitektur. Navnlig er det vigtigt at forstå at HTTP som grundlæggende princip er stateless, dvs. der gemmes ikke nogen former for oplysninger mellem hver interaktion mellem server og klienter.

Læs også dette gode svar på et spørgsmål om hvad stateless vil sige.

Interaktionsdesign

I første omgang vil vi lave en meget simpel app. Der skal indledningsvis være et søgefelt, hvor man søger på afgange. Når man trykker [enter] kommer der et søgeresultat, når man klikker på et søgeresultat, sættes afgangsdestinationen.

Der fremkommer nu et søgefelt til ankomst. Man søger på samme måde som med afgang, hvorefter der kommer en knap der hedder “vis rejse”. Når man klikker på den ser man mulige rejser fra rejseplanen.

Teknologier

Rejseplanens API

Rejseplanen har et åbent API, hvor nysgerrige nørder kan få adgang til at bruge deres databaser og søgefunktioner. Det gør de antageligt for at få nogle bud på hvordan interfaces (også) kunne se ud. Man husker også, at Rejseplanen er ejet af de forskellige trafikselskaber – deres formål er altså at understøtte offentlig transport. Dermed kan man sige, at deres data for deres ejeres vedkommende først og fremmest skal bruges så meget som muligt, så tæt på kundernes behov og ønsker som muligt.

Når man anvender API’et, vil man hurtigt opdage hvor komplekst det underliggende databasesystem skal være, for at person x i byen y, kan komme smertefrit i gang med sin rejse til destinationen z. Det er fascinerende, men også interessant i et udviklingsperspektiv; Vi skal (gudskelov) ikke give os i kast med at bygge systemet, vi skal bare bruge det til at komme med et bud på hel eller delvis funktionalitet.

Mens vi gør det, overholder vi naturligvis Rejseplanens retningslinjer for databrug, hvor der indledningsvis står:

Retningslinjerne for brugen af Rejseplanens data tager udgangspunkt i idéen ”Use it – don’t abuse it!” , hvilket betyder at vi gør data tilgængeligt med en forventning om at du vil bruge data med respekt for både Rejseplanen og de kunder der modtager dit slutprodukt

https://help.rejseplanen.dk/hc/da/articles/213633029

Om ReST Api’er

Rejseplanen API er et såkaldt ReST api, dvs et api som bygger på en særlig arkitektur; For det første betyder det at kommunikationen ikke husker noget om klienten fra gang til gang, du kan for eksempel ikke sætte nogle parametre op på serveren, eller automatisk få besked fra API’et om at noget er forandret etc. Dette kaldes en stateless arkitektur.

HTTP: er ligeledes en stateless protokol. Websockets som vi ofte bruger mellem node.js og klienter er derimod ikke stateless. Her opretholdes der faktisk en “sluse”, som man løbende kan kommunikere gennem. Sessions på en mySql server er en anden måde at oprette et state på hen over http kald.

Node

Node.js er en javascript baseret webserver, som kan udvides næsten i det uendelige med package manageren NPM.

NPM Socket.io er en klient server baseret socket-model til node. Bruges til at lave lynhurtig interaktion mellem klienter og serveren.

NPM Express gør det nemt at sætte en server op med node. Styrer hvilken port der lyttes på og hvilke filer der “hostes”. Kan også udvides til at styre bl.a database funktionalitet.

NPM Request gør det nemt at lave api-kald over http med node. Bruges her til at lave kald til api’et.

Stylesheet framework: Milligram

Projektet implementerer css boilerplaten Milligram. Det betyder i denne kontekst at knapper og skrifttyper er pæne, men vi udnytter ikke i øvrigt funktionalitet.

Opret en generisk request funktion

Med NPM request kan man altså nemt kalde en url udefra og få returneret for eksempel selve indholdet på en hjemmeside. Prøv for eksempel at køre følgende kode fra node.js:

var request = require('request');
request('http://www.google.com', function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body) // Print the google web page.
}
})

Som du kan se, returnerer google serveren rå html, som vi jo normalt plejer at parse med browseren – her logger vi det altså.

For at lave et kald til et api bruger vi samme funktion. Bemærk at funktionen får tre ting tilbage: en evt fejlbesked, en response header og et body element. Typisk er det sidstnævnte vi har brug for, men de andre er gode at kende. Lad os prøve at printe response.headers i stedet for body elementet.

Prøv også response.statusCode. Statuskoder er en vigtig del af http protokollen. Det er dem som styrer interaktionen mellem klienter og servere.

Lad os nu i stedet for at kalde Google.com prøve med et api. Base-url’en til rejseplanen er som nævnt ikke noget der skal offentliggøres, men i får den udleveret i timen. I dokumentationen til API’et kan man læse hvordan man opbygger en søgning på en lokation:

http://<base-url>/location?format=json&input=user%20input 

Prøv at indsætte det i din kode, og erstat med den rigtige baseUrl og et eller andet userinput, fx roskilde, og se hvad du får tilbage. Forhåbentlig en hel masse tekst i konsollen – men ikke særlig læseligt, og desværre heller ikke json. I API’ets dokumentation kan vi læse at man kan sætte output formatet til json ved at tilføje en såkaldt querystring – altså sådan en variabel efter spørgsmålstegnet i en url:

http://<base-url>/location?format=json&input=user%20input

Nu får vi json tilbage, men denne måde at skrive metoden på, er ikke særlig generisk. Vi vil gerne kunne søge på alt muligt – også andre mapper end location – så det er på tide vi bygger nogle variable op til en søgefunktion:

Læs her hvordan request.get skal opbygges. Lad os altså prøve at opbygge søgningen med variable:

let baseUrl = "http://xmlopen.rejseplanen.dk/bin/rest.exe";
let service = "location";
let searchString = "roskilde";
request({
baseUrl: baseUrl,
url: "/" + service,
qs:{
input: searchString,
format:'json'
}
}

Til sidst putter vi det hele ind i en funktion – searchApi – så vi kan kalde ting i api’et når vi kommunikerer med klienter.

Udvid funktionen med flere parametre

Når vi skal hente mere komplekse ting i api’et – for eksempel rejsebeskrivelser – skal det have nogle flere parametre med i søgestrengen. Kig i api’et og se hvor mange parametre der skal på et request for at hente rejseforslag mellem to destinationer.

Tilføj parametrene som variable i funktionen. Tænk på at i skal nå frem til en søgestreng der for eksempel ser således ud:

http:///trip?originId=8600626&destCoordX=&destCoordY=&destCoordName=&date=19.09.10&time=07:02&useBus=0

Parse JSON

Når vi modtager JSON fra en server, er resultatet altid en almindelig string. For at lave resultatet om til et JSON objekt vi kan løbe igennem, bruger vi JSON parse:

A common use of JSON is to exchange data to/from a web server. When receiving data from a web server, the data is always a string. Parse the data with JSON.parse(), and the data becomes a JavaScript object.

https://www.w3schools.com/js/js_json_parse.asp

Husk altså at funktionen, inden den sender data tilbage til klienten, skal kalde JSON.parse på objektet.