Rest APIs - mobile spezifische Herausforderungen

25

Ich arbeite an einem neuen iOS-App-Projekt auf der mobilen Seite. Es gibt einige Architekturänderungen und es stellt sich heraus, dass wir uns auf eine benutzerdefinierte private API stützen müssen, die von der App, die wir erstellen, und auch von anderen Clients wie einer Website verwendet wird.

Die API, die entworfen wird, folgt dem Rest-Stil von ressourcenzentrierten URI- und CRUD-Operationen, die HTTP-Verben zugeordnet sind. Dinge wie:

GET www.example.com/books
DELETE www.example.com/books/482094
POST www.example.com/users/6793

Das Problem ist, dass dieser Stil häufig dazu führt, dass der mobile Client viele Anforderungen zum Laden eines einzelnen App-Bildschirms oder zum Verwalten einer einzelnen Benutzeroberflächenaktion ausführen muss. Dies führt dazu, dass sich die App 8 Sekunden lang im Lademodus befindet, bis sie alles Nötige hat. Eine langsame und nicht reagierende App.

Mobile Clients haben gravierende Einschränkungen in Bezug auf die Konnektivität. Daher sollten wir im Idealfall diese Art von Regel befolgen:

1 Bildschirm == 1 API-Aufruf

1 save == 1 API-Aufruf.

Es gibt viele Situationen, in denen Sie auf einen Kollisionskurs mit den REST-Konstruktionsprinzipien gebracht werden, zum Beispiel:

  • Nehmen wir an, Ihre App ist seit einem Tag offline und Sie müssen mit vier Tabellen der Back-End-Datenbanken synchronisieren und benötigen einen Anruf wie www.example.com/sync_everything?since=2015-07-24
  • Nehmen wir an, es gibt einen Bildschirm, auf dem der Benutzer viele seiner Objekte bearbeiten kann, zum Beispiel Aufgaben in seiner Aufgabenliste ankreuzen kann. Es sollte eine Möglichkeit geben, alle diese Aufgabendatensätze in einem einzigen Stapel-API-Aufruf zu bearbeiten, anstatt nur einen API-Aufruf pro Bearbeitung.
  • Nehmen wir an, es gibt einen Bildschirm, der Informationen aus den DB-Tabellen ORDER, SALESMEN und PRODUCT mischt. Ich sollte diese Daten in einem Aufruf anstelle von drei abrufen.

Das Risiko ist, dass wir möglicherweise die restloseste API und die nutzloseste nicht reagierende mobile App haben, die es gibt.

Die Sache ist, ich bin nur ein neuer Auftragnehmer dort und was ich brauche, ist etwas, das mir dabei hilft, diese Punkte zu verdeutlichen, einige Artikel aus angesehenen Quellen oder ähnliches. Hauptakteure, die für ihren mobilen Client Kompromisse mit dem REST-Stil eingehen (z. B .: Verwendung von Endpunkten mit zusammengesetzten API-Aggregaten).

Oder irgendeine Lösung für dieses allgemeine Problem. Vielen Dank!

MikaelW
quelle
3
Es hört sich so an, als würde Ihre Frage lauten: "Wie kann eine API Sammlungen von Objekten und eingebetteten Objekten mit ähnlichen oder unterschiedlichen Typen bereitstellen, während der REST-Stil beibehalten wird?" Verstehe ich Ihre Frage?
Joshp
Ich glaube, die allgemeine Antwort ist, dass jeder REST-Aufruf eine Vielzahl von optionalen Parametern annehmen muss, damit er flexibel und dennoch relativ intuitiv ist. Die Synchronisierung ist immer schwierig, aber bei normalen Seiten werden normalerweise mehrere Aufrufe desselben Typs angezeigt, dh alle GETs, oder?
Ixrec
1
Ich denke, die Anpassung Ihrer API ist die falsche Lösung, wenn das Problem darin besteht, dass keine parallelen Anforderungen vorliegen - 8 kleine Anforderungen sind nicht viel schlimmer als eine große Anforderung, wenn sie nicht aufeinander warten müssen. Können Sie zu HTTP / 2 wechseln? Oder zumindest HTTP / 1.1-Pipelining verwenden?
Amon
Siehe auch: Muster für die Behandlung von Batch-Operationen in REST-Webservices? . Der Schlüssel besteht darin, zu identifizieren, welche Arten von Befehlen (und unter welchen Voraussetzungen) ohne Konflikte zusammengefasst werden können, und anschließend eine JSON-Darstellung der Stapelreihenfolge zu erstellen und diese zu senden. Es verliert die Hauptattraktivität für REST, nämlich die Cachefähigkeit, aber die Cachefähigkeit ist nicht immer für alle Arten von Anwendungen relevant. Beachten Sie, dass Batch / Concurrency nicht anwendbar ist, wenn logische Abhängigkeiten vorliegen.
rwong
Eine Analogie für die Situation, in der der Vermittler mehrere Operationen in einer Sequenz ausführen muss, mit nicht trivialen logischen Abhängigkeiten von jeder vorhergehenden Operation, ist so etwas wie "gespeicherte Prozedur", die in diesem Vermittler anstatt in einer Datenbank ausgeführt wird. Darunter darf der Vermittler einen einzelnen "Stored Procedure" -Aufruf in so viele RESTful-Anforderungen wie erforderlich konvertieren, dies ist jedoch ein Implementierungsdetail des Vermittlers.
rwong

Antworten:

27

Die API, die entworfen wird, folgt dem Rest-Stil von ressourcenzentrierten URI- und CRUD-Operationen, die HTTP-Verben zugeordnet sind.

Dies ist genau hier Ihr Problem.

Sie haben Ihre Ressourcen auf die Modelle in Ihrer Datenbank beschränkt (ich gehe davon aus). Das Laden all dieser Ressourcen nimmt daher einige Zeit in Anspruch, da auf Ihrem Server kein Konzept für Ressourcen vorhanden ist, für die in der Datenbank keine Repräsentation vorhanden ist.

Zum Beispiel könnte haben

www.example.com/books/482094
www.example.com/books/582045
www.example.com/books/427454
www.example.com/books/319343

Das alles muss geladen werden, um meine Bibliothek zu bekommen

Dies ist kein Problem mit RESTful-Design, sondern ein REST-Anti-Pattern. Es gibt absolut nichts in REST, was besagt, dass unsere Ressourcen eine Eins-zu-Eins-Zuordnung zu irgendetwas anderem in Ihrem System haben müssen, einschließlich Datenbankmodellen.

Die Lösung besteht darin, mehr Ressourcen zu erstellen, die besser zu dem passen, was Sie laden möchten. Wenn Sie 5 Ressourcen haben, die immer zusammen enden, erstellen Sie eine neue Ressource, die die Informationen für diese 5 Ressourcen enthält.

Was Sie haben sollten, ist so etwas

www.example.com/users/334/my_library

das lädt nur alle Bücher für diesen Benutzer. "my_library" ist kein Modell in Ihrer Datenbank, aber es ist eine Ressource. Der Server erstellt es basierend auf Modellen in der Datenbank, es gibt jedoch keine 1-zu-1-Zuordnung, und der Server verfügt über die Flexibilität, diese Ressource zu erstellen, ohne das DB-Modell zu ändern.

Sie könnten auch haben

www.example.com/users/334/favioured_books
www.example.com/users/334/books_ordered_last_week
www.example.com/users/334/wishlist

Keines davon muss als Modell in Ihrer Datenbank oder Ihrem Domänenbereich vorhanden sein.

Es gibt ein weit verbreitetes Missverständnis, dass dies die falsche Vorgehensweise ist, da Frameworks wie Rails die Zuordnung von Ressourcen zu Modellen im Domänenbereich, die wiederum 1 zu 1 mit Datenbankzeilen zugeordnet sind, im Verhältnis 1 zu 1 lehrten. Dies ist weder notwendig noch wird es empfohlen.

Die Ressourcen sollten zahlreich, billig und leicht sein . Es sollte einfach sein, sie zu erstellen, und sie sollten von Ihrem Domain-Modell abstrahiert sein. Wenn Sie einen neuen benötigen, erstellen Sie einfach einen neuen. Wenn Sie Probleme damit haben, liegt es nicht an REST, sondern an Ihrem Framework.

Die große Einschränkung dabei ist natürlich, ob Ihr Framework dies zulässt. Frameworks wie Rails und Django, die den Kurs zur 1-zu-1-Zuordnung absolviert haben, um "Zeit zu sparen", erschweren dies. Aber das ist ein Fehler bei den Frameworks, nicht bei RESTful Design.

Hier ist Jim Webber, der dies ausführlicher bespricht (einschließlich einiger Grabungen bei Rails auch!)

https://yow.eventer.com/yow-2011-1004/domain-driven-design-for-restful-systems-by-jim-webber-1047

Cormac Mulhall
quelle
Das ist sehr interessant und ich stimme dem voll und ganz zu, aber leider bin ich nicht derjenige, der die API ausführt, und ich habe wenig Einfluss darauf, wenn überhaupt. Viele Leute werden dieses "Anti-Pattern" überall verwenden (aus vielen Gründen, da es sich um eine Framework-Einschränkung handelt) und sie verwenden einfach die URI-Definition, um klar über ihre Datenbank nachzudenken. Die API-Endpunkte sind nur eine weitere Möglichkeit, ihre Datenbank zu visualisieren. In einigen Fällen ist es auch schwierig, eine Ressource wie die von Ihnen beschriebene zu erstellen, da Objekte sehr unterschiedlich sind. Ihre Benennung würde zu sehr vagen Begriffen führen.
MikaelW
Um vom Standpunkt der Effizienz aus auf das Problem zurückzukommen, waren sie sich einig, dass bei einem sehr langsamen mobilen Bildschirm (und nur dann) einige kombinierte Aufrufe möglich sind, sie sich jedoch in einer Komponente befinden, die die API umschließt ( anstatt der API selbst) wird nur von den mobilen Clients verwendet und wird nicht als Teil der Kern-API, der Kerndomäne, betrachtet.
MikaelW
@MikaelW, du hast recht. Sogar was Cormac sagte, ist das ideale Szenario. Manchmal arbeiten Sie mit einer API, die für viele andere Systeme (Desktop, Mobile, Web, geplante Jobs, Legacy-Systeme usw.) erforderlich ist. Diese Art von API muss sehr flexibel sein und Ressourcen bereitstellen, um möglichst viele Möglichkeiten zu erfüllen, kann jedoch nicht alle spezifischen Leistungsanforderungen von einem Verbraucher erfüllen. In diesem Fall haben Sie nicht viele Möglichkeiten ...
Dherik