Einmal half ich einem Freund, der Daten über freie und bewohnte Wohnungen aus dem Hausverwaltungssystem in den Standort seines Kunden integrieren musste. Zu meiner Freude hatte dieses System eine API. Aber leider war es sehr schlecht arrangiert.
Ich habe beschlossen, diesen Artikel nicht zu schreiben, um das zu diskutierende System zu kritisieren, sondern um darüber zu sprechen, welche Fehler bei der Entwicklung der API auftreten, und um Möglichkeiten zur Korrektur dieser Fehler vorzuschlagen.
Situationsübersicht
Die betreffende Organisation verwendete das
Beds24- System zur Verwaltung des Wohnraums. Informationen darüber, was kostenlos ist und was beschäftigt ist, wurden mit verschiedenen Reservierungssystemen für Unterkünfte (wie Buchung, AirBnB und andere) synchronisiert. Die Organisation war an der Entwicklung des Standorts beteiligt und wollte, dass bei der Suche nur Informationen zu den für einen bestimmten Zeitraum verfügbaren und in der Kapazität geeigneten Räumen angezeigt werden. Diese Aufgabe schien sehr einfach zu sein, da Beds24 eine API für die Integration mit anderen Systemen bereitstellt. Tatsächlich stellte sich heraus, dass die Entwickler dieser API viele Fehler im Design gemacht haben. Ich schlage vor, diese Fehler zu analysieren, spezifische Probleme zu identifizieren und darüber zu sprechen, wie die Entwicklung der API in den betrachteten Situationen angegangen werden kann.
Problem Nr. 1: Textformat anfordern
Da der Kunde nur an Informationen interessiert ist, ob beispielsweise ein Hotelzimmer frei oder besetzt ist,
/getAvailabilities
wir nur auf den API
/getAvailabilities
. Obwohl ein Aufruf einer solchen API zu Daten über die Verfügbarkeit von Räumen führen sollte, sieht dieser Aufruf tatsächlich wie eine POST-Anforderung aus, da der Autor der API beschlossen hat, Filter als JSON-Hauptteil der Anforderung zu akzeptieren. Hier ist eine Liste möglicher Abfrageparameter und Beispiele für die Werte, die sie akzeptieren:
{ "checkIn": "20151001", "lastNight": "20151002", "checkOut": "20151003", "roomId": "12345", "propId": "1234", "ownerId": "123", "numAdult": "2", "numChild": "0", "offerId": "1", "voucherCode": "", "referer": "", "agent": "", "ignoreAvail": false, "propIds": [ 1235, 1236 ], "roomIds": [ 12347, 12348, 12349 ] }
Lassen Sie uns durch dieses JSON-Objekt gehen und darüber sprechen, was hier falsch ist.
- Daten (
checkIn
, lastNight
und checkOut
) liegen im Format checkOut
. Es gibt absolut keinen Grund, das Standardformat ISO 8601 ( YYYY-MM-DD
) bei der Konvertierung von Datumsangaben in Zeichenfolgen nicht zu verwenden, da dies ein weit verbreiteter Standard für die Darstellung von Datumsangaben ist. Vielen Entwicklern ist dies bekannt. Viele JSON-Parser erwarten dies bei der Eingabe. Darüber hinaus besteht das Gefühl, dass das Feld lastNight
redundant ist, da es ein checkOut
Feld gibt, das immer durch ein Datum einen Tag vor dem in lastNight
angegebenen Datum lastNight
. Im Zusammenhang mit den oben genannten Mängeln schlage ich vor, beim Entwerfen solcher APIs zu versuchen, immer Standardmethoden für die Darstellung von Daten zu verwenden und API-Benutzer nicht mit der Notwendigkeit zu belasten, mit redundanten Daten zu arbeiten. - Alle Bezeichnerfelder sowie die
numChild
numAdult
und numChild
sind numerisch, werden jedoch als Zeichenfolgen dargestellt. In diesem Fall gibt es keinen offensichtlichen Grund, sie als Zeichenfolgen darzustellen. - Hier sehen Sie die folgenden
roomId
: roomId
und roomIds
sowie propId
und propIds
. Das Vorhandensein von roomId
und propId
ist redundant, da beide zur Übertragung von Kennungen verwendet werden können. Außerdem gibt es ein Problem mit Typen. Bitte beachten Sie, dass das Feld roomId
ein Zeichenfolgenfeld ist und die numerischen Werte der Bezeichner im Array roomIds
verwendet werden müssen. Dies kann zu Verwirrung und Problemen beim Parsen führen und legt außerdem nahe, dass auf dem Server einige Vorgänge mit Zeichenfolgen und einige mit Zahlen ausgeführt werden, obwohl diese Zeichenfolgen und Zahlen zur Darstellung derselben verwendet werden Daten.
Ich möchte API-Entwickler einladen, zu versuchen, das Leben derjenigen, die diese APIs verwenden, nicht zu verkomplizieren, während sie Fehler beim Entwerfen von APIs machen, die den oben beschriebenen ähnlich sind. Man sollte nämlich nach einer Standarddatenformatierung streben, um sicherzustellen, dass sie nicht redundant sind, um sicherzustellen, dass verschiedene Datentypen nicht zur Darstellung homogener Entitäten verwendet werden. Und es ist nicht alles wert, wahllos in Form von Linien zu präsentieren.
Problem Nr. 2: Antwortkörperformat
Wie bereits erwähnt, interessieren wir uns nur für den API
/getAvailabilities
. Schauen wir uns an, wie die Antwort auf diesen Endpunkt aussieht, und sprechen wir darüber, welche Mängel während seiner Entstehung entstanden sind. Denken Sie daran, dass wir beim Zugriff auf die API an einer Liste von Objektkennungen interessiert sind, die für einen bestimmten Zeitraum kostenlos sind und eine bestimmte Anzahl von Personen aufnehmen können. Unten finden Sie ein Beispiel für den Hauptteil der Anforderung an die API und ein Beispiel dafür, was als Antwort auf diese Anforderung zurückgegeben wird.
Hier ist die Anfrage:
{ "checkIn": "20190501", "checkOut": "20190503", "ownerId": "25748", "numAdult": "2", "numChild": "0" }
Hier ist die Antwort:
{ "10328": { "roomId": "10328", "propId": "4478", "roomsavail": "0" }, "13219": { "roomId": "13219", "propId": "5729", "roomsavail": "0" }, "14900": { "roomId": "14900", "propId": "6779", "roomsavail": 1 }, "checkIn": "20190501", "lastNight": "20190502", "checkOut": "20190503", "ownerId": 25748, "numAdult": 2 }
Sprechen Sie über Antwortprobleme.
- Im Antworttext wurden die
numAdult
ownerId
und numAdult
plötzlich zu Zahlen. Und in der Anfrage war es notwendig, sie als Zeichenfolgen anzugeben. - Die Liste der Immobilienobjekte wird in Form von Objekteigenschaften dargestellt, deren Schlüssel
roomId
( roomId
) sind. Es wäre logisch zu erwarten, dass solche Daten als Array ausgegeben werden. Für uns bedeutet dies, dass wir, um eine Liste der verfügbaren Räume zu erhalten, das gesamte Objekt roomsavail
müssen, während wir prüfen müssen, ob bestimmte Eigenschaften der darin enthaltenen Objekte vorhanden sind, z. B. roomsavail
, und nicht auf etwas wie checkIn
und lastNight
. Dann wäre es notwendig, den Wert der roomsavail
zu überprüfen, und wenn er größer als 0 ist, könnten wir daraus schließen, dass die entsprechende roomsavail
zur Buchung verfügbar ist. Schauen wir uns nun die Eigenschaft roomsavail
. Hier sind die Optionen für die Darstellung im Antworttext: "roomsavail": "0"
und "roomsavail": 1
. Sehen Sie das Muster? Wenn die Räume belegt sind, wird der Eigenschaftswert durch eine Zeichenfolge dargestellt. Wenn frei - wird daraus eine Zahl. Dies kann in Sprachen, die eng mit Datentypen zusammenhängen, zu vielen Problemen führen, da in denselben Sprachen keine Werte unterschiedlicher Typen verwendet werden sollten. In Verbindung mit dem Vorstehenden möchte ich Entwicklern vorschlagen, Arrays von JSON-Objekten zu verwenden, um bestimmte Datensätze darzustellen, und keine unbequemen Konstruktionen in Form von Schlüssel-Wert-Paaren zu verwenden, die der hier betrachteten ähnlich sind. Darüber hinaus muss sichergestellt werden, dass die Felder homogener Objekte keine Daten unterschiedlichen Typs enthalten. Eine ordnungsgemäß formatierte Serverantwort sieht möglicherweise wie folgt aus. Bitte beachten Sie, dass bei der Darstellung von Daten in diesem Formular die Rauminformationen keine doppelten Daten enthalten.
{ "properties": [ { "id": 4478, "rooms": [ { "id": 12328, "available": false } ] }, { "id": 5729, "rooms": [ { "id": 13219, "available": false } ] }, { "id": 6779, "rooms": [ { "id": 14900, "available": true } ] } ], "checkIn": "2019-05-01", "lastNight": "2019-05-02", "checkOut": "2019-05-03", "ownerId": 25748, "numAdult": 2 }
Problem 3: Fehlerbehandlung
So ist die Fehlerbehandlung in der hier betrachteten API organisiert: Das System sendet Antworten mit einem Code von
200
an alle Anforderungen, auch wenn ein Fehler auftritt. Dies bedeutet, dass die einzige Möglichkeit, eine normale Antwort von einer Antwort mit einer Fehlermeldung zu unterscheiden, darin besteht, den Hauptteil der Antwort zu analysieren und zu überprüfen,
errorCode
error
oder
errorCode
sind. In der API werden nur die folgenden 6 Fehlercodes bereitgestellt.
Beds24 API-FehlercodesIch schlage vor, dass jeder, der dies liest, versucht, keine Antwort mit Code 200 (erfolgreiche Verarbeitung der Anfrage) zurückzugeben, wenn während der Verarbeitung der Anfrage ein Fehler aufgetreten ist. Sie können diesen Schritt nur ausführen, wenn er vom Framework bereitgestellt wird, auf dessen Grundlage Sie die API entwickeln. Durch die Rückgabe geeigneter Antwortcodes können API-Clients im Voraus wissen, ob sie den Antworttext analysieren müssen oder nicht und wie dies zu tun ist (dh ob eine normale Serverantwort oder ein Fehlerobjekt analysiert werden soll).
In unserem Fall gibt es zwei Möglichkeiten, die API in diese Richtung zu verbessern: Sie können entweder für jeden der 6 möglichen Fehler einen speziellen HTTP-Code im Bereich von 400 bis 499 angeben (am besten), oder im Fehlerfall den Code 500 zurückgeben, der dies zulässt Zumindest sollte der Client vor der Analyse des Antwortkörpers wissen, dass er Informationen über den Fehler enthält.
Problem Nummer 4: "Anweisungen"
Nachfolgend finden Sie die „Anweisungen“ zur Verwendung der API aus der Projektdokumentation:
Bitte lesen Sie die folgenden Anweisungen, wenn Sie die API verwenden.
- API-Aufrufe sollten so konzipiert sein, dass während ihrer Ausführung eine minimale Datenmenge gesendet und empfangen werden muss.
- API-Aufrufe werden einzeln ausgeführt. Sie müssen bis zum nächsten Aufruf der API warten, bevor Sie den nächsten Aufruf tätigen.
- Wenn Sie mehrere Aufrufe an die API ausführen müssen, sollte zwischen diesen eine Pause von einigen Sekunden vorgesehen werden.
- API-Aufrufe müssen nicht zu oft ausgeführt werden, um die Anzahl der Aufrufe auf dem Mindestniveau zu halten, das zur Lösung von Clientaufgaben erforderlich ist.
- Eine übermäßige Nutzung der API innerhalb von 5 Minuten führt zur Sperrung Ihres Kontos ohne zusätzliche Benachrichtigungen.
- Wir behalten uns das Recht vor, Kunden, die unserer Meinung nach die API übermäßig nutzen, den Zugriff auf das System zu sperren. Dies erfolgt nach unserem Ermessen und ohne weitere Ankündigung.
Obwohl die Punkte 1 und 4 durchaus gerechtfertigt erscheinen, kann ich den anderen Punkten dieser Anweisung nicht zustimmen. Betrachten Sie sie.
- Artikelnummer 2. Wenn Sie eine REST-API entwickeln, wird davon ausgegangen, dass es sich um eine zustandsunabhängige API handelt. Die Unabhängigkeit von API-Aufrufen von früheren Aufrufen ist einer der Gründe, warum die REST-Technologie in Cloud-Anwendungen breite Anwendung gefunden hat. Wenn ein bestimmtes Modul des Systems den Status nicht unterstützt, kann es im Fehlerfall problemlos erneut bereitgestellt werden. Systeme, die auf solchen Modulen basieren, lassen sich leicht skalieren, wenn sich die Belastung ändert. Wenn Sie eine RESTful-API entwerfen, sollten Sie sicherstellen, dass es sich um eine zustandsunabhängige API handelt und dass sich diejenigen, die sie verwenden, nicht darum kümmern müssen, jeweils nur eine Anforderung auszuführen.
- Artikelnummer 3. Dieser Artikel sieht ziemlich seltsam und mehrdeutig aus. Ich kann den Grund nicht verstehen, warum dieser Absatz der Anweisung geschrieben wurde, aber ich habe das Gefühl, dass er uns sagt, dass das System bei der Verarbeitung der Anforderung bestimmte Aktionen ausführt und wenn es durch eine andere Anforderung „abgelenkt“ wird, nicht rechtzeitig gesendet, kann dies ihre Arbeit beeinträchtigen. Die Tatsache, dass der Autor des Handbuchs „einige Sekunden“ sagt, ermöglicht es uns außerdem nicht, die genaue Dauer der Pause herauszufinden, die zwischen aufeinanderfolgenden Anforderungen aufrechterhalten werden muss.
- Artikel Nr. 5 und Nr. 6. Es bezieht sich auf "übermäßige Nutzung der API", es werden jedoch keine Kriterien für "übermäßige Nutzung" angegeben. Vielleicht sind es 10 Anfragen pro Sekunde? Oder vielleicht 1? Darüber hinaus können einige Webprojekte sehr viel Verkehr haben. Wenn sie ohne angemessene Gründe und ohne Benachrichtigung den Zugriff auf die benötigte API schließen, werden ihre Administratoren die Verwendung solcher APIs höchstwahrscheinlich ablehnen. Wenn Sie solche Anweisungen schreiben, verwenden Sie eine klare Sprache und setzen Sie sich an die Stelle der Benutzer, die mit Ihrem System arbeiten müssen, und richten Sie sich dabei nach Ihren Anweisungen.
Problem Nummer 5: Dokumentation
So sieht die API-Dokumentation aus.
Beds24 API-DokumentationDas einzige Problem mit dieser Dokumentation ist das Erscheinungsbild. Es würde viel besser aussehen, wenn es gut formatiert wäre. Insbesondere um das mögliche Erscheinungsbild einer solchen Dokumentation zu zeigen, habe ich mit
Dillinger und weniger als zwei Minuten Zeit die folgende Version davon erstellt. Meiner Meinung nach sieht es viel besser aus als oben.
Verbesserte DokumentationUm solche Materialien zu erstellen, wird empfohlen, Spezialwerkzeuge zu verwenden. Wenn es sich um einfache Dokumente handelt, die den oben beschriebenen ähnlich sind, reicht eine reguläre Markdown-Datei für ihr Design völlig aus. Wenn die Dokumentation komplizierter ist, verwenden Sie für das Design am besten Tools wie
Swagger oder
Apiary .
Übrigens, wenn Sie sich die Dokumentation für die Beds24-API ansehen möchten, schauen Sie
hier .
Problem 6: Sicherheit
Die Dokumentation für alle API-Endpunkte lautet wie folgt:
Um diese Funktionen nutzen zu können, muss der Zugriff auf die API zulässig sein. Dies erfolgt im Menü EINSTELLUNGEN → KONTO → KONTOZUGRIFF.In der Realität kann jedoch jeder auf diese API zugreifen und mithilfe einiger Aufrufe Informationen von ihr abrufen, ohne Anmeldeinformationen anzugeben. Dies gilt beispielsweise auch für Fragen zur Verfügbarkeit bestimmter Wohnungen. Dies wird in einem anderen Teil der Dokumentation erläutert.
Die meisten JSON-Methoden erfordern einen API-Schlüssel für den Zugriff auf ein Konto. Der API-Zugriffsschlüssel kann über das Menü EINSTELLUNGEN → KONTO → KONTOZUGRIFF festgelegt werden.Neben der unverständlichen Erklärung von Authentifizierungsproblemen stellt sich heraus, dass der Benutzer den Schlüssel für den Zugriff auf die API selbst erstellen muss (dies erfolgt übrigens durch manuelles Ausfüllen des entsprechenden Felds, einige Mittel zum automatischen Erstellen von Schlüsseln werden nicht bereitgestellt). Die Schlüssellänge muss zwischen 16 und 64 Zeichen liegen. Wenn Sie Benutzern erlauben, ihre eigenen Schlüssel für den Zugriff auf die API zu erstellen, kann dies dazu führen, dass sehr unsichere Schlüssel angezeigt werden, die leicht abgerufen werden können. In einer ähnlichen Situation sind Probleme mit dem Inhalt der Schlüssel möglich, da Sie alles in das Schlüsselfeld eingeben können. Im schlimmsten Fall kann dies zu einem Angriff auf den Dienst mit SQL Injection oder ähnlichem führen. Lassen Sie Benutzer beim Entwerfen einer API keine Schlüssel für den Zugriff auf die API selbst erstellen. Generieren Sie stattdessen automatisch Schlüssel für sie. Der Benutzer sollte nicht in der Lage sein, den Inhalt eines solchen Schlüssels zu ändern, aber er sollte gegebenenfalls in der Lage sein, einen neuen Schlüssel zu generieren und den alten als ungültig zu erkennen.
Bei Anforderungen, die eine Authentifizierung erfordern, tritt ein weiteres Problem auf. Es besteht darin, dass ein Authentifizierungstoken als Teil des Anforderungshauptteils gesendet werden muss. So wird es in der Dokumentation beschrieben.
Beds24 API-AuthentifizierungsbeispielWenn das Authentifizierungstoken im Anforderungshauptteil übertragen wird, bedeutet dies, dass der Server den Anforderungshauptteil analysieren muss, bevor er den Schlüssel erreicht. Danach extrahiert er den Schlüssel, führt die Authentifizierung durch und entscheidet dann - was soll er mit der Anfrage tun - ob er sie erfüllt oder nicht. Wenn die Authentifizierung erfolgreich ist, wird der Server nicht zusätzlich belastet, da in diesem Fall der Anforderungshauptteil noch analysiert werden müsste. Wenn sich die Anforderung jedoch nicht authentifizieren konnte, wird wertvolle Prozessorzeit für das Parsen des Anforderungshauptteils umsonst aufgewendet. Es ist besser, ein Authentifizierungstoken im Anforderungsheader zu senden, das so etwas wie ein
Bearer- Authentifizierungsschema verwendet. Bei diesem Ansatz muss der Server den Anforderungshauptteil nur analysieren, wenn die Authentifizierung erfolgreich ist. Ein weiterer Grund, warum wir die Verwendung eines Standardschemas wie Bearer zur Authentifizierung empfehlen, ist die Tatsache, dass die meisten Entwickler mit solchen Schemata vertraut sind.
Problem Nummer 7: Leistung
Dies ist das letzte Problem auf meiner Liste, aber es beeinträchtigt nicht seine Bedeutung. Tatsache ist, dass es etwas mehr als eine Sekunde dauert, bis die Anforderung an die betreffende API abgeschlossen ist. In modernen Anwendungen können solche Verzögerungen nicht akzeptabel sein. In der Tat können Sie hier allen an der Entwicklung der API Beteiligten raten, die Leistung nicht zu vergessen.
Zusammenfassung
Trotz aller Probleme, über die wir hier gesprochen haben, konnten wir mit der fraglichen API die Probleme lösen, mit denen das Projekt konfrontiert ist. Die Entwickler haben sich jedoch viel Zeit genommen, um die API zu verstehen und alles zu implementieren, was sie benötigen. Um einfache Probleme zu lösen, mussten sie außerdem ziemlich komplizierten Code schreiben. Wenn diese API so entworfen würde, wie sie sollte, würde die Arbeit schneller erledigt und die schlüsselfertige Lösung wäre einfacher.
Daher möchte ich alle, die die API entwerfen, bitten, darüber nachzudenken, wie Benutzer ihrer Dienste damit arbeiten werden. Stellen Sie sicher, dass die Dokumentation für die API ihre Funktionen vollständig beschreibt, damit sie verständlich und gut gestaltet ist. Kontrollieren Sie die Benennung von Entitäten und stellen Sie sicher, dass die Daten, die Ihre API sendet oder empfängt, klar strukturiert sind, damit Sie einfach und bequem mit ihnen arbeiten können. Vergessen Sie außerdem nicht die Sicherheit und den korrekten Umgang mit Fehlern. Wenn Sie beim Entwerfen der API alles berücksichtigen, worüber wir gesprochen haben, müssen Sie nicht so etwas wie die seltsamen "Anweisungen" schreiben, die wir oben besprochen haben, um damit zu arbeiten.
Wie bereits erwähnt, soll dieses Material die Leser nicht davon abhalten, Beds24 oder ein anderes System mit einer schlecht gestalteten API zu verwenden. Mein Ziel war es, Beispiele für Fehler und Lösungsansätze aufzuzeigen und Empfehlungen abzugeben, nach denen jeder die Qualität seiner Entwicklungen verbessern kann. Ich hoffe, dass dieses Material die Aufmerksamkeit von Programmierern auf sich zieht, die es auf die Qualität der von ihnen entwickelten Lösungen lesen. Dies bedeutet, dass es weltweit mehr gute APIs geben wird.
Liebe Leser! Sind Sie auf schlecht gestaltete APIs gestoßen?