p.blog
Unternehmenskultur, Softwareentwicklung und Architektur

04.22.2020

Deine Consumer hassen deine API?

6 Minuten Lesedauer

Jetzt mal ganz unter uns: Du gehst voll mit dem Trend, öffnest dein System „nach außen“ mit einer RESTful-HTTP-Schnittstelle, das Ganze auch noch im agilen Ansatz – und dann das! Die Consumer beschweren sich. Dabei hast du deine Schnittstelle sogar dokumentiert und passt sie zeitnah an neue Anforderungen und Feedback an! WARUM also hasst jemand deine API?

 

Vielleicht haben die Consumer einfach keine Ahnung. Vielleicht hilft dir aber auch unser nicht zu ernst gemeinter Hass-Katalog. Dafür nehmen wir nachfolgend die Ich-Perspektive deines (ziemlich motzenden) API Consumers ein.

Ich bin dein Consumer – und ich hasse deine API, weil …

 

… meine Anwendung alle paar Wochen unerwartet abbricht, da deine API plötzlich anders reagiert

Es ist ja schön, dass du mit jedem Sprint „Verbesserungen“ und neue Features einbaust. Allerdings bin ich schon überrascht, wenn plötzlich mehr Informationen (z.B. neue Attribute) in der Response geliefert werden.  Und ja, es ist toll, dass du sogar deine API-Beschreibung entsprechend angepasst hast. Aber ich habe eigentlich kein Monitoring darauf aufgesetzt. Und wenn du dann evtl. noch neue bzw. andere Fehlercodes zurückschickst oder Pagination einbaust, dann sind das für mich wirklich „breaking changes“!

Also ein Vorschlag zur Güte: Für mich ist es total okay, wenn ich in meinem Request (z.B. in der URL) eine Versionsnummer angebe – und von Zeit zu Zeit aktiv umschalten muss, weil du eine alte Version abschaltest. Aber bitte – versioniere deine API und halte zumindest eine Zeit lang alte Versionen parallel am Leben. Dann kann ich in Ruhe umbauen und testen und mich dann sogar über neue Features freuen. Ach so: Und vielleicht könntest du mich sogar aktiv über neue Versionen und Sundowns benachrichtigen, z.B. auf dem Portal, auf dem du deine API publiziert hast, in der API Response oder ganz traditionell per Newsletter (siehe auch How to Smartly Sunset and Deprecate APIs)?

 

… deine API immer mit HTTP Response Code 200 antwortet

HTTP Response Codes sind doch keine hohe Wissenschaft [Anmerkung der Autorin: im Detail manchmal schon 😉]. Ich mach es mal ganz einfach und begrenze mich zumindest auf drei Hauptgruppen und ein paar Beispiele aus jeder Gruppe:

 

200 (OK)NEIN, das ist kein möglicher Response Code im Fehlerfall (und du schickst einfach Fehlerdetails im Response Body mit)!
204 (NO CONTENT)Ist OK, wenn ich z.B. ein DELETE geschickt habe – aber dann bitte wirklich ohne Content (Response Body).

 

 

OK, auch ich bin nicht unfehlbar. Dabei wäre es schön, wenn du mir hilfst meinen Fehler zu erkennen. Es darf gern etwas detaillierter sein als immer nur HTTP Status Code 400.

 

400 (BAD REQUEST)Ich habe also einen Request geschickt, der nicht der Schnittstellenbeschreibung entspricht.
Ein definiertes Fehler-Objekt im Response Body wäre schön. Vielleicht sogar mit automatisch auswertbaren Codes und Details und nicht nur mit deutschen, sich ständig ändernden Beschreibungen!

{ 
  "error": "INVALID_SEARCH_FIELD", 
  "message": "The color you searched for is not a valid one.",
}
401 (NOT AUTHORIZED)Da muss ich wohl wirklich mal prüfen, ob ich den falschen API Key oder ein abgelaufenes Access Token schicke.

403 (FORBIDDEN)

 

OK, vielleicht habe ich versucht etwas zu tun, was ich nicht darf? Vielleicht habe ich auch mehr Anfragen gestellt als ich durfte? Dann wäre aber auch eine 429 (TOO MANY REQUESTS) schön gewesen.
418 (I´M A TEAPOT)Haha. Kannst du dir solche Scherze wirklich leisten?

 

 

Ich weiß, dass das unangenehm ist, aber falls das Problem bei dir bekannt ist, wären ein paar Details schon schön – und damit meine ich nicht deinen internen Stacktrace!

 

500 (INTERNAL SERVER ERROR)Verstanden, du hast gerade selbst keine Ahnung, warum es nicht geht.

 

503 (SERVICE UNAVAILABLE)Das indiziert mir, dass du evtl. aufgrund von Überlastung oder Wartungsarbeiten nicht antworten kannst – das ist doch mal eine Aussage. Ich versuche es später nochmal. (Wenn ich mir noch etwas wünschen darf: Eine „Retry-After“-Information in der Antwort wäre super.)

 

… meine Requests ewig brauchen bis zur Antwort

Wenn du die Anfrage (nach Ausschöpfen von anderen Performanz-Verbesserungen durch Caching o.ä.) wirklich nicht so schnell verarbeiten kannst, dann ist vielleicht eine asynchrone Verarbeitung besser – ggf. mit HTTP Response 202 (ACCEPTED). Gib mir eine Referenz zurück und ich kann ggf. periodisch nach dem Status fragen.

 

… ich schon mehrfach durch hohe Last einen Crash deiner API verursacht habe

 

Wenn du mir deine SLAs (Service Level Agreements) mitteilst, kann ich das zumindest auch auf meiner Seite berücksichtigen.
Schutzmechanismen wie Circuit Breaker, Spike Arrests und Quotas sollten das auf deiner Seite jedoch zusätzlich sicherstellen.

 

… ich dich erst anschreiben muss, um dir zu sagen, dass deine API gerade nicht funktioniert

So ein providerseitiges Monitoring ist eine feine Sache – aber ich verstehe, dass consumer-driven Alerting die einfachere Variante ist. Aber nur für dich als Provider und ganz bestimmt nicht für mich.

 

… deine API unvollständig dokumentiert ist und ich daher HTTP-Response-400-Pingpong spielen muss

Ich erkenne keine Unterscheidung von optionalen und Pflichtfeldern, Attribute mit nur zwei möglichen Werten sind nur als String (statt Enumeration – siehe auch OpenAPI Spec: Enums) definiert und sämtliche Fehlerfälle fehlen in deiner Dokumentation komplett. Um diese Informationen zumindest für Request-Objekte zu bekommen, schicke ich alle möglichen Request-Kombinationen gegen deine API und schaue, wann ich HTTP Response 400 bekomme. Statt dessen wäre sowas schön:

paths: 
  /persons: 
    get: 
      parameters: 
        - in: query 
          name: surname 
          required: true 
          description: surename of the person you are searching for 
          schema: 
            type: string 
        - in: query 
          name: sort 
          description: alphabetical sort order of persons by surname 
          schema: 
            type: string 
            enum: [asc, desc]

 

Außerdem ist keine Beschreibung deiner SLAs enthalten (gibt es z.B. Quota-Restriktionen) und die Security ist auch nicht definiert (ja, auch falls es nur ein API Key ist).  Dass die Endpunkte für alle Umgebungen fehlen (für Produktion und – wünschenswerterweise auch – Test oder Tryout), ist dabei dann das kleinste Problem.

 

… ich deine API nicht testen kann

Ich baue eine super Anwendung und binde deine API ein. Kompiliert, fertig. Für Testzwecke generiere ich mir aus deiner API-Dokumentation (OpenAPI und Swagger Tools sei Dank) sogar einen Mock Server, gegen den ich teste. So weit, so gut. Aber irgendwie möchte ich schon noch ein paar wirkliche Integrationstests durchführen. Aber leider hast du keinen Test- bzw. Tryout-Endpunkt, auf den ich zugreifen kann. Vielleicht hast du den aber sogar, ich kann jedoch nicht testen, weil ich selbst kein Resource Owner bin. D.h. mir gehören keine Daten und aufgrund der Autorisierung darf ich auf keinerlei Daten zugreifen – ich kann z.B. Fahrzeugdaten nicht auslesen, weil ich selbst kein Testfahrzeug bei dir habe.

 

Darum …

Stell dir vor, du wärst ein Consumer und wünschst dir eine gute API. Und dann versuche diese Wünsche auch als Provider umzusetzen. Vielleicht helfen dir folgende Guidelines dabei:

  • Erstelle ein consumerfreundliches API Design – vergiss die Fehlerfälle nicht!
  • Versioniere deine API
  • Implementiere eine robuste und stabile Anwendung
  • Monitore deine API selbst und reagiere proaktiv auf Probleme
  • Dokumentiere so, als würdest du deine API nicht kennen
  • Ermögliche Tests
  • Informiere deine Consumer über Änderungen und auch Probleme

 

 

Vielleicht werden deine API Consumer dich trotzdem nicht lieben – aber hoffentlich deine API 😉Und wenn du ein Consumer bist und kräftig in jeder Zeile genickt hast: Stell dir vor, DU wärst der API Provider.