7. Persistenz, Autorisierung, Cookies

7.7 Web-APIs von Drittanbietern verwenden

Konzeptuell wird dieses Kapitel nichts wirklich Neues einführen. Ziel ist es, ein Mini-Frontend zu bauen, das eine "echte" Web-API verwendet. Als Beispiel habe ich hierfür GeoDB gewählt. Dies ist eine API, über die Sie sich z.B. Listen von Städten holen können.

Authorisierung Für viele APIs müssen Sie sich authorisieren, und bei intensiver oder kommerzieller Nutzung auch: beazahlen! Bei RapidApi können Sie sich einen Nutzer-Account anlegen und dann bei GeoDB die "Basic Subscription" für $0.00 im Monat wählen. Die Funktionalität der API ist dann zwar beschränkt, für unsere Lernzwecke reicht es allerdings.

Sie erhalten dann einen API-Key, mit dem Sie sich bei jedem Request authorisieren müssen. Der Browser (oder wer auch immer die Requests an die GeoDB-Api tätigt), muss in jedem Request den API-Key mitsenden. Wie wird dieser übermittelt?

  1. Bei RapidAPI wird im Http-Header die Zele X-RapidAPI-Key: g4br8vfw7v7nrepfomxv gesetzt (kein echter Schlüssel hier sondern Zufallsstring).
  2. Bei AccuWeather wird der API-Key direkt als Query-Parameter in der URL angegeben: http://dataservice.accuweather.com/locations/v1/regions?apikey=g4br8vfw7v7nrepfomxv
  3. Cookies können im Allgemeinen wohl nicht verwendet werden: der Browser schickt die bei CORS-Requests normalerweise nicht mit. Würde er dies tun, entstünden tausend Sicherheitslücken.

Methode 2 ist etwas unsicherer als Methode 1: wenn der Key direkt in der URL drinsteht, ist er für jedermann sichtbar, kann in Bookmarks gespeichert (und während der Raucherpause vom bösen Bürokollegen gelesen) werden. Allerdings ist es für Lernzwecke schön, weil man dann die API-Requests einfach über die Adresszeile eingeben kann; mit Methode 1 geht das nicht, da müssen Sie immer den Header setzen, was mit Ajax einfach geht, aber eben nicht per Browser-Adresszeile.

Übungsaufgabe Legen Sie einen RapidAPI-Zugang an, abbonieren GeoDB für $0.00 im Monat und speichern Sie sich Ihren API-Key.

Gehen Sie auf GeoDB Cities, der Spezifikation für den Endpoint https://wft-geo-db.p.rapidapi.com/v1/geo/cities. Lesen Sie sich durch, welche Parameter ("Optional Parameters") der Query-String beinhalten kann.

Schauen Sie sich geodb-cityname.html an. Mann kann den Namen einer Stadt eingeben (oder einen Präfix). Daraufhin bekommt man eine Liste der Städte, auf die der Name passt. Oder besser gesagt, die ersten 10. Oder noch besser gesagt, man bekommt einen String im JSON-Format, der eine Liste der ersten 10 solcher Städte enthält.

Lesen Sie sich das JSON-Format durch. So lernen Sie das Format kennen, in welchem die GeoDB-API unsere Anfragen beantwortet. Schauen Sie nun in den Quelltext von geodb-cityname.html und speichern sich die Seite lokal auf Ihrem Rechner.

Übungsaufgabe Ändern Sie die Seite so, dass man sich Surchgebnisse \(n+1 \dots n+10\) zeigen lassen kann. Hinweis: achten Sie auf den Query-Parameter offset.

Übungsaufgabe Fügen Sie Ihrer Seite Links bzw. Knöpfe prev und next hinzu, mit denen man sich die vorherigen 10 bzw. nächsten 10 Treffer anzeigen lassen kann.

Übungsaufgabe Ändern Sie Ihre Seite: die Suchergebnisse sollen nicht mehr roh als JSON angezeigt werden, sondern schön als Tabelle mit folgenden Spalten: Name, (Breitengrad, Längengrad), Einwohnerzahl

Übungsaufgabe Erweitern Sie Ihre Seite: beim Klick auf eine Stadt soll die lokale Zeit angezeigt werden. Hierfür brauchen Sie den Endpoint /v1/geo/cities/{CITYID}/dateTime. Die Referenz dafür finden Sie auf GeoDB Cities unter dem Punkt City Date-Time.

Übungsaufgabe Legen Sie auf AccuWeather einen Zugang an und machen sich mit der API vertraut. Schreiben Sie ein Frontend, auf dem der User den Namen einer Stadt eingeben soll. Daraufhin soll eine Tabelle erstellt werden, die alle Städte mit diesem Namen auflistet und für jede die folgenden Daten darstellt:

  • Geographische Lage (Breitengrad, Längengrad, Höhe über dem Meeresspiegel),
  • Tagestiefst- und Tageshöchsttemperatur.

Hierfür brauchen Sie zwei Endpoints:

Im Frontend versus im Backend

Der Nachteil aller Apps, die wir in diesem Teilkapitel geschrieben haben, war, dass entweder der Nutzer den API-Key haben und eingeben muss oder wir als Entwickler ihn hart in den Code unserer Seite einbinden müssen. Letzteres ist natürlich schlecht, denn dann ist er ja allen öffentlich zugänglich. Verlagern wir nun die Kommunikation mit dem der API in ein Backend.

Übungsaufgabe Schreiben Sie einen Server, der die beiden Endpoints /get-cities-by-prefix und /get-local-time anbietet und dann die Anfrage an die GeoDB-API weiterleitet und den Response an die Webseite des Nutzers. Am Frontend müssen Sie fast nichts ändern, nur der URLs Ihrer Ajax-Requests müssen Sie anpassen.

Hierzu müssen Sie wissen, wie man in Node.js einen HTTP-Request erstellt und behandelt. Ich verwende für diese Vorlesung das Paket axios. Sie können sich an dem Endpoint "/get-cities" in server.js in 13-login-server.zip orientieren (das ist neu; Sie müssen die zip-Datei also eventuell erneut herunterladen). Alternativ hier der Code zur Orientierung:

const axios = require('axios');
app.get("/get-cities", async function (req, res) {

  const query = url.parse(req.url, true).query;
  let n = parseInt(query.n) || 0;
  let result = { result: fib(n) };

  const options = {
    method: 'GET',
    url: 'https://wft-geo-db.p.rapidapi.com/v1/geo/cities',
    headers: {
      'X-RapidAPI-Key': '3004920d14msh6d79ab4e117d68ep130870jsn456d0c3abdd6',
      'X-RapidAPI-Host': 'wft-geo-db.p.rapidapi.com'
    },
    params: { limit: 2, namePrefix: "Berli", offset: 30 }
  };

  try {
    const response = await axios.request(options);
    console.log(response.data);
    res.send(JSON.stringify(response.data));
  } catch (error) {
    console.log("http request to wft-geo-db has failed");
    return res.send("http request to wft-geo-db has failed");
  }
});