Jenseits von REST Maturitäts-Leveln:
Erkenntnisse aus einem REST API Projekt
IPC München, 25. Oktober 2016
© David Buchmann
Wir haben eine "Herausforderung"
- Daten in Enterprise Systemen
- Webseiten sind Aufwändig zu entwickeln
- Daten Zugriff ist sehr langsam
- Daten sind über viele Systeme verteilt
Daten Ausliefern
API: Symfony Anwendung
- FOSRest: Routing, Content Negotiation
- ElasticSearch Datenabfragen
- JMSSerializer: JSON zu Model zu JSON / XML
API: Versionierung
- JMSSerializer Feature: In Model mapping
- FOSRest bestimmt API Version aus
query string / accept header
- Neue Version nur für inkompatible Änderungen
- Alternatives:
- Elasticsearch index pro Version
- Alte Versionen der Applikation weiter laufen lassen
Nur ab Version 2
/**
* The description as HTML
*
* @Serializer\Since("2")
* @Serializer\Type("string")
*/
public $description;
Api-Version: 2
Für alte Versionen
/**
* Plain text version of description.
*
* @Serializer\Until("1")
* @Serializer\Type("string")
* @Serializer\VirtualProperty
* @Serializer\SerializedName("description")
*/
public function getDescriptionPlaintext() {
return strip_tags($this->description);
}
Varnish Cache
- Skalieren bei vielen Anfragen
- Superschnelle Antworten
Varnish Cache: Zugriffskontrolle
- Basic authentication mit htpasswd Datei
- Symfony schreibt die Datei aus der User Tabelle
- Varnish verwendet sie mit dem basic auth plugin
- FOSHttpCache user context: Cache geteilt zwischen Usern mit denselben Berechtigungen
Varnish Cache: Routing
- Single point of entry, Sub-Pfade werden an verschiedene Backends geleitet
- Unsere Applikation läuft auf hhvm - probe und fallback auf PHP
Varnish Cache: Cache Hits Verbessern
- Api-Version Header und v query parameter
- Accept Header und Format in URL
- Normalisieren von Accept-Language
- Normalisieren von Accept-Encoding
- Cookies entfernen falls möglich
- vcl_error um früh abzubrechen bei Fehlern
Bringt die Entwickler dazu, eure API zu Benutzen
Dokumentation
- Selbsterklärende Namen ist eine faule Ausrede
- Zusammenhänge dokumentieren
- Tutorials
- Changelog und Migrationshinweise
NelmioApiDocBundle
class LabelController {
/**
* @ApiDoc(
* description="Get a single label",
* output={
* "class"="App\Model\Label",
* "groups"={"api"}
* },
* section="Products")
*/
public function getAction($id)
Swagger 2?
- SwaggerPhp - leider ohne Symfony Integration
Indexierung der Daten
Workflow
Architektur
- Loader (batches):
SOAP / REST / csv / XML / SQL
- Persistor
- Indexer
Symfony Commands
- Commands für einzelne Aufgaben
- Meta commands für ganze Abläufe
- Commands als Services
- Supervisord für permanent laufende Worker
RabbitMQ
- Informieren von anderen Services
- Entkoppeln von Teilaufgaben
- Retry queues
RabbitMQ & PHP
| php-amqplib | amqp extension |
---|
Installation: | Alles in PHP | PHP Extension |
Verbindung: | Jeder Request neu | 1 pro php-fpm Prozess |
Heartbeat: | Invalid Frame 65 | Blockierendes warten - kill funktioniert nicht |
Datenqualität
- Regeln zum Auswählen der Daten
- Regeln, wenn ganzer Eintrag ignoriert werden soll
- Blacklist API um kurzfristig fehlerhafte Einträge zu verstecken
Monitoring und Diagnose
- API für Zugriff auf Rohdaten für Fehlersuche
- API Funktion für Daten Status
- Zentrales Logging mit graylog
- statsd Varnish plugin
- OpsGenie
Elasticsearch
Elasticsearch: Indexes
- Separater Index pro Sprache
- Alles de-normalisiert für schnelle Antworten
- Keine joins oder parent-child Relationen
Elasticsearch: Schema-Änderungen
- ES errät Einstellungen für undefinierte Felder
- Nicht immer korrekt => Manuelle Definitionen
- Bestehende Index Definition kann nicht geändert werden
- Neuen Code auf Server stellen ohne online zu schalten
- Neuen Index erzeugen, Daten übernehmen
(vom alten Index oder von MySQL)
Elasticsearch: Clustering
- ES läuft auf mehreren Servern
- Instanzen kommunizieren miteinander
- Indexes sind sharded
- Automatische Aggregation und load balancing
Ausblick
Über REST hinaus
- Aggregierte Information, für spezifischen Client optimiert
- + Weniger Requests, weniger Bandbreite.
- - Engere Kopplung, Server hat mehr Aufwand.
- Mehrschichtige Architektur: App API
Alternativen: Stateless, aber...
- React und data pull APIs
- Falcor:
Graph als JSON, angeben der gewünschten Datenfelder
- GraphQL:
Schema für Graph Daten, Abfrage-Sprache
Danke!
@dbu
David Buchmann, Liip AG