Nur noch kurz die Welt retten … ein API bauen

Teil 1: Eine Einführung in Apigility
Kommentare

Auf der ZendCon 2013 wurde erstmals das auf dem Zend Framework 2 basierende Projekt Apigility vorgestellt. Damit können auf einfache Weise APIs erstellt und betrieben werden, um z. B. in mobilen Anwendungen direkt vom Frontend angesprochen zu werden. Anfang Mai 2014 ist nun das erste stabile Release erschienen. Es ist also an der Zeit, sich intensiver mit Apigility auseinanderzusetzen.

Damit Sie die Beispiele selbst nachvollziehen können, steht eine Beispielanwendung auf GitHub für Sie bereit. Sie können das Projekt wie folgt klonen (bitte ggf. die Verzeichnisse anpassen) und installieren:

cd /home/devhost
git clone htt ps://github.com/RalfEggert/phpmagazin.apigility
cd phpmagazin.apigility
git checkout step1
php composer.phar selfupdate
php composer.phar install

Um die Installation abzuschließen, müssen Sie noch die Schreibrechte für einige Verzeichnisse anpassen, damit Apigility Änderungen vornehmen kann:

> sudo chmod 777 -R config/
> sudo chmod 777 -R data/
> sudo chmod 777 -R module/

Zum Schluss muss Apigility mit php public/index.php development enable in den Entwicklungsmodus gebracht werden. Danach richten Sie noch einen Virtual Host für die Adresse phpmagazin.apigility ein. Wenn Sie nun htt p://phpmagazin.apigility/ in Ihrem Browser aufrufen, sollte die Seite ungefähr wie in Abbildung1 dargestellt aussehen. Zu guter Letzt müssen Sie noch eine MySQL-Datenbank anlegen und dort einen Dump aus der Datei /data/sql/mysql.dump.sql einspielen. Alternativ können Sie auch jede andere Datenbank verwenden, die vom Zend Framework 2 und damit von Apigility unterstützt wird.

Abb. 1: Willkommen auf phpmagazin.apigility

Abb. 1: Willkommen auf phpmagazin.apigility

 

Als Beispiel wollen wir ein kleines API für ein Tippspiel zur Fußballweltmeisterschaft 2014 umsetzen. Wenn Sie den Datenbank-Dump eingespielt haben, können Sie die Struktur der Anwendung genauer betrachten. Es gibt insgesamt drei Tabellen, wie Sie Abbildung 2 entnehmen können. Alle Listings zu diesem Artikel, die nicht im Magazin abgedruckt sind, finden Sie sowohl auf GitHub als auch im Repository im Verzeichnis /listings/. Nun können wir loslegen.

Abb. 2: Die Tabellen für unser Projekt

Abb. 2: Die Tabellen für unser Projekt

 

Was ist Apigility überhaupt? Mit Apigility können Sie qualitativ hochwertige APIs erstellen und betreiben. Beim Einsatz eines API für die Datenhaltung können Sie diese sehr einfach von der Präsentationslogik trennen. Somit können Sie mobile Websites und Applikationen im Frontend entwickeln und die Daten mithilfe von Apigility per REST- oder RPC-Web-Service anbinden. Die Rückgabe der angeforderten Daten erfolgt im JSON-Format, das clientseitig von JavaScript verarbeitet werden kann. Apigility setzt auf dem Zend Framework 2 auf und bietet einige sehr interessante Features: • RESTful Web Services • RPC Web Services • Datenformat JSON bzw. JSON HAL • Versionierung • Codebasierte und datenbankbasierte Services • Problemdetails für HTTP-API • Datennormalisierung und -validierung • Authentifizierung per HTTP Basic/Digest und OAuth2 • Dokumentation per HTML und Swagger Für diesen Beitrag wurde Apigility 1.0.3. verwendet. Die Pläne für die kommende Version 1.1 lassen sich ebenfalls sehen, dazu zählen Anbindungen an Doctrine und MongoDB, HTTP Caching und das automatische Erkennen der Datenbank. Vielleicht ist das neue Release bereits erschienen, wenn Sie diesen Artikel lesen. Zur weiteren Einführung sollten Sie sich bei Gelegenheit auch die Videos zu Apigility anschauen. Darin wird unter anderem der Einstieg in die Software erläutert sowie gezeigt, wie Sie eine Dokumentation für Ihr API bereitstellen können. Zudem bietet die Website eine ausführliche Dokumentation von Apigility sowie Hinweise zum Download und zur Installation.

Unser erstes API

Um beginnen zu können, klicken Sie auf der Startseite von http://phpmagazin.apigility/ auf den Button „Get Started!“ Der folgende Bildschirm zeigt uns eine Übersicht über alle bereits eingerichteten APIs und deren Einstellungen. Wir beginnen mit den Einstellungen für den Datenbankadapter und wählen deshalb aus dem Seitenmenü den Punkt „Database Adapters“ und danach den Button „Create New DB Adapter“ aus. Vergeben Sie einen Namen für Ihren Adapter, wählen einen Treibertyp aus und geben Datenbanknamen sowie alle Zugangsdaten ein. Nach dem Klicken auf den Button „Create DB Adapter“ wird Ihr Datenbankadapter angelegt. Wenn Sie den Adapter nach dem Speichern nochmals anklicken, sollte es in etwa wie in Abbildung 3 aussehen.

Abb. 3: Unser erster Adapter

Abb. 3: Unser erster Adapter

 

Wir möchten zuerst mit der Tabelle „teams“ beginnen, die alle teilnehmenden Mannschaften an der WM enthält, und dafür ein API erstellen, das nur lesende Zugriffe erlaubt. Dafür rufen Sie aus dem Hauptmenü den Punkt „APIs“ auf und klicken auf den Button „Create New API“. Als Namen verwenden wir „WM2014API“. Sollte Ihnen nach dem Speichern kein API in der Liste angezeigt werden, laden Sie die Seite in Ihrem Browser bitte einmal neu, um das neue API auszuwählen. Sie haben an dieser Stelle die Möglichkeit, einen REST- oder einen RPC-Service zu erstellen und die Autorisierung sowie die Versionierung zu konfigurieren. Klicken Sie bitte auf den Punkt „REST Services“ im Seitenmenü und danach auf den Button „Create New REST Service“. Da wir eine Datenbank anbinden möchten, klicken Sie bitte den Reiter „DB-Connected“ an und wählen den bereits erstellten Datenbankadapter aus. Bei dem Tabellennamen geben Sie „teams“ ein und klicken auf den Button „Create DB-Connected REST Service“. Jetzt können wir unser API schon das erste Mal testen. Für den Test eines RESTful Web Service gibt es viele Möglichkeiten. Als sehr beliebtes Mittel zum Zweck hat sich der Postman Rest Client gemausert, der im Chrome-Browser als App installiert und genutzt werden kann. Alternativ können Sie auch den RESTClient oder cURL auf der Kommandozeile verwenden. Wenn Sie Postman gestartet haben, geben Sie bei Request-URL http://phpmagazin.apigility/teams ein und wählen GET als HTTP-Request-Modus aus. Klicken Sie jetzt auf den „Send“-Button, und Sie sollten eine JSON-Struktur zurückerhalten, die in etwa wie in Abbildung 4 aussehen sollte. Bei dieser besonderen JSON-Struktur handelt es sich um HAL JSON. HAL steht für „Hypermedia Application Language“ und ist eine offene Spezifikation zur Beschreibung einer generischen Struktur für RESTful-Ressourcen. Apigility sendet die Daten dafür mit dem generischen Media-Type application/hal+json zurück. In dieser Struktur ist eine Eigenschaft _links enthalten, die in unserem Beispiel die Request-URLs für die aktuelle, die erste, die letzte und die nächste Seite enthält. Die eigentlichen Daten finden sich in der Eigenschaft _embedded, wobei die einzelnen Entitäten wieder über eine Eigenschaft _links verfügen. Ganz am Ende der Struktur wird noch die Anzahl der Seiten, die Anzahl der Entitäten pro Seite sowie die Anzahl aller Entitäten zurückgegeben. Mit diesen Angaben ist es sehr einfach, eine Paginierung der Daten umzusetzen. Weitere Informationen zu HAL finden Sie auch in der Apigility-Dokumentation.

Abb. 4: Das Ergebnis der ersten Anfrage an unser API

Abb. 4: Das Ergebnis der ersten Anfrage an unser API

 

Wenn Sie den Request-URL im Postman auf http://phpmagazin.apigility/teams/ger ändern und die Anfrage absenden, erhalten Sie übrigens direkt die Daten einer Entität. Bei einzelnen Entitäten finden sich die Eigenschaften nicht unter _embedded sondern direkt auf oberster Ebene. Zudem wird unter _links nur der Request-URL für die aktuelle Entität zurückgegeben.

RESTful Service konfigurieren

Nun möchten wir uns daran machen, diesen RESTful Service zu konfigurieren. Dafür rufen Sie in Apigility den neu erstellten REST Service teams auf. Wenn Sie den Mauszeiger über den Eintrag bewegen, erscheinen ein grüner Button zum Ändern sowie ein roter zum Löschen des REST Service. Klicken Sie bitte auf den grünen Button. Bei den „General Settings“ ändern Sie bitte die Anzahl der Entitäten pro Seite von dem Standardwert 25 auf 32. Damit wollen wir die Paginierung der Teams verhindern und immer alle 32 Mannschaften zurückerhalten. Bei den HTTP-Methoden für Entitäten und Collections lassen Sie bitte nur den Haken bei GET stehen. Damit verhindern wir, dass die Daten der Mannschaften über unseren REST Service geändert werden können. In den anderen Bereichen können Sie die Einstellungen für die Datenbank, die REST-Parameter, das Format der zu übertragenen Daten sowie einige Klassennamen verändern. Wenn Sie statt HAL JSON lieber natives JSON zurückerhalten möchten, können Sie dies z. B. unter „Content Negotiation“ ändern. Das möchten wir an dieser Stelle aber nicht tun, stattdessen speichern Sie bitte Ihre Änderungen. Öffnen Sie nun den Reiter „Fields“ und wechseln Sie wieder in den Editiermodus. Legen Sie ein neues Feld „id“ an und klicken auf „Create New Field“. Klicken Sie das neue Feld an, und Sie sollten die Einstellungen für dieses Feld ändern können. Da wir für die Mannschaften keine Änderungen zulassen möchten, ist an dieser Stelle nur die Beschreibung des Felds interessant. Geben Sie dort „Team identifier“ ein. Minimieren Sie danach das Feld „id“ wieder und legen Sie noch die Felder „title“ und „code“ an und vergeben Sie eine sinnvolle Beschreibung für jedes der Felder. Speichern Sie Ihre Änderungen wieder und wechseln Sie dann auf dem Reiter „Documentation“ in den Editiermodus. Auf diesem Reiter können wir nun die Dokumentation unseres REST Service konfigurieren. Geben Sie zuerst eine Beschreibung für den REST Service ein, z. B. „REST service to retrieve team collections and entities.“. Danach legen Sie die passende Beschreibung für die Collection allgemein sowie für die GETHTTP-Methode. Die Dokumentation für den Response Body können Sie mithilfe des Buttons „generate from configuration“ automatisch erstellen lassen. Danach wiederholen Sie den Vorgang für die Beschreibung der Entity und speichern alle Angaben. Um die Dokumentation anschauen zu können, rufen Sie im Menü den Punkt „API Docs“ auf. Danach wählen Sie für unser API die Version „v1“, und Sie sollten ein ähnliches Ergebnis wie in Abbildung 5 erhalten. Weitere Informationen zur Dokumentation Ihres API finden Sie im Manual. Damit ist die Konfiguration des REST Service für die Mannschaften abgeschlossen.

Abb. 5: Die Dokumentation unseres API

Abb. 5: Die Dokumentation unseres API

 

Aufbau des API-Moduls

Das durch Apigility automatisch generierte Modul folgt dem normalen Aufbau eines ZF2-Moduls. Wenn Sie sich das neue API-Modul „WM2014API“ genauer anschauen möchten, checken Sie per Git bitte den Branch „step2“ aus: git checkout step2. Sie finden dort eine Datei Module.php, wobei der konkrete Code im Verzeichnis /src/ des Moduls liegt. In Listing 1 finden Sie die Modulklasse. Das Besondere an diesem Modul ist die konkrete Implementierung vom ZFApigilityProviderApigilityProviderInterface. Durch die Implementierung dieses Interface wird das Modul für Apigility aktiviert. Im Verzeichnis /config/ des Moduls finden sich zwei Dateien. Die Datei documentation.config.php enthält die Dokumentation für das API-Modul (Listing 2 auf GitHub). Die Konfiguration des Moduls finden Sie wiederum in der Datei module.config.php (Listing 3 auf GitHub). Sie unterscheidet sich deutlich von der Konfiguration eines „normalen“ ZF2-Moduls. Darin enthalten ist unter anderem die Konfiguration der Routen für unsere Services, die API-Versionen, der REST-Controller, der Ausgabeformate, der Datenbankadapter und der Validierung. Die Klassen für die einzelnen Versionen des API finden sich im Verzeichnis /src/.

 array(
        'namespaces' => array(
          __NAMESPACE__ => __DIR__,
        ),
      ),
    );
  }
}

Bisher haben wir einen REST Web Service erstellt – dafür wurden Klassen für eine Collection und eine Entität erstellt. Diese können Sie bei Bedarf auch mit weiterer Funktionalität erweitern.

REST Service für Spiele anlegen

Wenn Sie den step2-Branch ausgecheckt haben, können Sie zur Übung nun den REST Service für die Spiele anlegen. Als Basis dient dafür die Datenbanktabelle „matches“, die Sie für die Einrichtung des DB Connected REST Service verwenden. Wichtig ist, dass Sie kein neues API erstellen, sondern nur einen weiteren REST Service für das WM2014API-API anlegen sollen. Stellen Sie die maximale Anzahl der Ergebnisse pro Seite auf 48 ein (in der Datenbank ist nur die Vorrunde der WM 2014 angelegt) und lassen Sie nur Anfragen per GET-Methode zu. Definieren Sie alle Felder, die die Tabelle „matches“ bereitstellt und geben Sie für jedes Feld eine Beschreibung an. Zum Schluss erstellen Sie noch die Dokumentation für Collections und Entities. Speichern Sie alle Änderungen ab und prüfen Sie im Anschluss das Ergebnis mithilfe von Postman. Als Request-URL verwenden Sie http://phpmagazin.apigility/matches für eine Collection und http://phpmagazin.apigility/matches/2 für das Eröffnungsspiel der WM. Wenn die Einrichtung des REST Service funktioniert hat, sollten Sie die entsprechenden Daten zurückerhalten. Alternativ können Sie auch den Branch „step3“ auschecken, um Ihr Ergebnis vergleichen zu können.

REST Service mit ZF2 abrufen

Ebenfalls in diesem Branch enthalten ist ein kleines Frontend-Modul „WM2014Bet“, das eine Übersicht der Spiele zeigt. Rufen Sie dafür im Browser die Adresse http://phpmagazin.apigility/wm2014-bet auf, und Sie sollten eine Seite ähnlich wie in Abbildung 6 erhalten. Sie können sich die einzelnen Spiele auch direkt anzeigen lassen, indem Sie auf den entsprechenden Button klicken. Der Abruf der beiden REST Services ist in den Model-Services des Moduls gekapselt. In Listing 4 finden Sie den WM2014BetServiceMatchService, der die Daten für die Spiele bereitstellen soll. Die beiden Methoden fetchAll() und fetchOne() senden dafür einen GET Request ab. Die entsprechende Methode sendGetRequest() ist im abstrakten Service WM2014BetServiceAbstractService definiert, den Sie in Listing 5 finden. Der Aufruf erfolgt mithilfe von ZendHttpClient, und die Antwort wird mit ZendJsonJson dekodiert. In Listing 6 finden Sie abschließend noch eine Factory, die den MatchService konfiguriert. Darin wird der vollständige URL für den abzurufenden REST Service definiert und als vollständige REST-Route an den MatchService übergeben.

Abbildung 6

Abbildung 6

 

 

restRoute = $restRoute;
  }

  public function getRestRoute()
  {
    return $this->restRoute;
  }

  public function fetchAll()
  {
    $matchesData = $this->sendGetRequest($this->getRestRoute());
    return $matchesData->_embedded->matches;
  }

  public function fetchOne($id)
  {
    $matchData = $this->sendGetRequest($this->getRestRoute() . '/' . $id);
    return $matchData;
  }
}
setMethod('get');
    $client->setHeaders(
      array(
        'Accept' => 'application/json',
      )
    );

    $response = $client->send();
    $response = $response->getContent();
    $data     = Json::decode($response);
    return $data;
  }
}
get('ViewHelperManager');
    $serverUrlHelper = $viewHelperManager->get('ServerUrl');
    $urlHelper = $viewHelperManager->get('Url');
    $restRoute = $serverUrlHelper() . $urlHelper('wm2014-api.rest.matches');
    $service = new MatchService();
    $service->setRestRoute($restRoute);
    return $service;
  }
}

Bei dieser Beispielimplementierung haben wir das Zend Framework 2 im Backend verwendet, um die REST Services abzurufen. Selbstverständlich lassen sich die REST Services auch im Frontend per JavaScript, z. B. durch den Einsatz von AngularJS, abrufen.

Im zweiten Teil der Einführung in Apigility beschäftigen wir uns mit dem Schreibzugriff für REST Services, mit der Authentifizierung und damit, wie man alles miteinander verbinden kann.

Weiter mit: Teil 2

Alle Teile: Teil 1, Teil 2

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -