Only use SOAP to wash your hands

Nicht, dass ich im Moment nichts Besseres zu tun hätte als zu bloggen. Tatsächlich hätte ich durchaus Besseres zu tun – ich müsste nämlich eigentlich weiter an der clientseitigen Implementierung einer API arbeiten, deren Realisierung sich nun schon seit längerem zieht wie Kaugummi, und die für mich ein – erneutes – Lehrstück ist, dessen Ergebnis @fhemberger so treffend mit Only use SOAP to wash your hands zusammenfasst, wofür ich herzlich danke.

Softwareentwicklung ist nicht unser Kerngeschäft, und von größeren Aufträgen in dem Bereich lassen wir auch typischerweise die Finger – da haben andere ihren Fokus. Häufig geht es aber um vergleichsweise kleine Projekte; oftmals von Agenturen, die das im Prinzip auch selbst könnten, aber aus verschiedenen Gründen (und sei es die wie immer knappe Zeit) an uns auslagern. Da sagen wir dann durchaus nicht nein, vor allem, wenn wir den Kunden und womit er so arbeitet bereits gut kennen.

Woran ich gerade arbeite, ist eine Sache, die sich auf dem Papier im Grunde überschaubar liest – was schließlich auch die Voraussetzung dafür ist, so etwas wie ein verlässliches Angebot abgeben zu können. Gleichzeitig ist es ein gutes Beispiel dafür, warum wir hier künftig wohl verstärkt auf einer Abrechnung auf Stundenbasis pochen werden, denn was uns hier bei einer vergleichsweise einfachen API vorgesetzt wurde, geht auf keine Kuhhaut. Insofern will ich hier auch gar nicht groß über SOAP selbst ranten – schon deshalb nicht, weil es aussichtslos wäre, sich mit dem grandiosen Rant The S stands for Simple messen zu wollen (ja, das ist als Lesebefehl aufzufassen). Nein, hier soll es um die konkrete SOAP-API gehen, mit der ich gerade zu arbeiten gezwungen bin und deren Bezeichnung und Hersteller ich lieber in den Mantel des Schweigens hülle.

Es geht um ein Projekt aus dem touristischen Bereich. Unser Kunde hat eine Datenbank mit Unterkünften (Hotels, Ferienwohnungen, etc.), und eine Unterkunft kann einen oder mehrere Raumtypen haben (z.B. Einzelzimmer, Doppelzimmer, etc.). Mit diesen Daten soll ein Portal gefüttert werden, an das sich unser Kunde gerne angebunden wissen möchte. Die API bietet eine Insert-, eine Update- und eine Delete-Funktion für die Unterkünfte, wobei hier jeweils Raumtypen als Unterelemente übergeben werden können. So weit, so gut – simples CRUD, wobei das R schickerweise weggelassen wurde. Aber damit kann man unter der gegebenen Aufgabenstellung klarkommen.

„Die Schnittstelle ist als SOAP über HTTP realisiert.“

Diesen Satz in der Einleitung zu lesen, ließ mich bereits erschaudern. SOAP ist für mich so ziemlich der Inbegriff von höllischer Bloatware und totaler Überkomplexität. Wer im 21. Jahrhundert normalerweise REST-APIs implementiert und dabei Datenstrukturen in schlanken Formaten wie JSON oder YAML verwendet, der fragt sich bei der Lektüre der SOAP-Spezifikation, was genau die Leute geraucht haben müssen, die sich freiwillig aufhalsen, ihre Datenstrukturen in XML abzubilden, dabei munter Namespaces einzuführen, XML-Schemas zu definieren, diese jetzt schon um etliche Faktoren aufgeblähte Struktur dann noch in einem SOAP-Body zu verpacken und diesen gemeinsam mit einem SOAP-Header in einen SOAP-Envelope zu stecken, der dann unter Zuhilfenahme des zusätzlichen HTTP-Headers „SOAPAction“ (von dem niemand so genau sagen kann, was der soll) an einen HTTP-Server zu schicken, der diesen ganzen Rotz (sorry …) dann erstmal validieren und dann in seine eigene Datenstruktur parsen muss, nur um bei der Antwort den umgekehrten Weg zu gehen.

Von Hand möchte man so etwas in keinem Fall implementieren. Es ist extrem aufwendig und auch fehlerträchtig, weshalb man sich für SOAP noch etwas Besonderes ausgedacht hat: Dienstbeschreibungen in Form von WSDL-Dateien, die vereinfacht gesagt maschinenlesbar dokumentieren, unter welcher URL eine API zu finden ist, welche Funktionen diese API beherrscht und wo man das XML-Schema finden kann, das die Datentypen beschreibt, die man übermittelt und zurückbekommt. Gedacht ist das so, dass man als Entwickler jene WSDL-Datei dem SOAP-Toolkit seiner Wahl zum Fraß vorwirft und jenes damit dann irgendetwas Sinnvolles macht, also z.B. dynamisch oder statisch irgendwelche Klassen generiert, die man dann in der Programmiersprache seiner Wahl mehr oder weniger „nativ“ benutzen kann, ohne sich um den riesigen Bloat hintendran kümmern zu müssen. Soweit die Theorie.

Was ich nun also in der Spezifikation lese, ist „SOAP“. Was ich nicht lese, ist „WSDL“. Ich beginne also schweren Herzens, die entsprechenden SOAP-Aufrufe manuell zu implementieren. Überraschung: Es funktioniert nicht – ich bekomme via SOAP eine sauber formatierte Fehlermeldung, dass es die (dokumentierte) API-Funktion auf dem Server nicht gäbe. Ich stelle eine Supportanfrage an den API-Provider. Ich warte von Dienstag bis zum darauffolgenden Montag auf Antwort und bekomme dann den überraschenden Hinweis: Die URL zur API würde nicht stimmen; ich müsste da noch ein ?wsdl anhängen.

Das ist nun schon mal obskur, denn unter dieser URL kann ich mitnichten die API ansprechen, wie der Mitarbeiter mir mitteilte, sondern erhalte – Überraschung – eine WSDL-Datei zum Download. Klasse, freue ich mich; wenigstens etwas, auch wenn das heißt, dass ich meine bisherige Handarbeit und vor allem die endlosen völlig fruchtlosen Tests umsonst gemacht habe. Ich werfe nun also den Klassengenerator an, der mir anstandslos binnen einer Sekunde ein dickes Bündel fertiger Klassen generiert, mit denen ich die SOAP-API nun bequem ansprechen kann.

Angeblich.

Alles, was ich von der API zurückbekomme, ist eine HTML-(!)-Seite mit dem Hostnamen als Inhalt. Das ist wahrlich keine valide SOAP-Nachricht, und mein Client schmiert entsprechend ab. Ich dokumentiere den kompletten HTTP-Request und die HTTP-Antwort und frage, was hier falsch sein soll; immerhin spreche ich hier die API exakt so an, wie die WSDL-Datei es vorgibt. Es ist immer noch Montag.

Ich warte auf Antwort bis zum darauffolgenden Mittwoch. Also dem Mittwoch eine Woche später. Mir wird mitgeteilt, dass man die Abläufe intern ein wenig umstrukturiert habe und ich nun einen neuen Ansprechpartner für die Schnittstelle hätte. (Ich kann an dieser Stelle schon mal ein wenig in die Zukunft greifen: Immer, wenn ich den neuen Ansprechpartner anschreibe, scheint dieser meine Anfragen intern weiterzuleiten und ich bekomme Antwort vom bisherigen Ansprechpartner. Aber schön, dass wir mal drüber geredet haben.)

Eine weitere Woche vergeht. Dann bekomme ich die überraschende Antwort des neuen Ansprechpartners, ich würde die falsche URL ansprechen. Huh..? entfährt es mir da beim Lesen, denn diese URL habe ich schließlich selbst nirgendwo angegeben – sie entstammt vielmehr direkt der WSDL-Datei des Anbieters. Ich weise freundlich auf diesen Umstand hin und bitte darum, dann doch bitte die WSDL-Datei zu korrigieren. Derweil mache ich das in Handarbeit und ersetze in den automatisch generierten Klassen anschließend manuell die Ziel-URL. Schön ist anders.

Nach einer Woche habe ich immer noch nichts gehört. Ich erlaube mir, vorsichtig nachzufragen, wann ich denn mit der aktualisierten WSDL-Datei rechnen könne. Und ich sende noch ein weiteres Bündel Fragen mit. Dazu gehört beispielsweise, warum Umlaute, die ich korrekt UTF8-kodiert (wie vorgeschrieben) an das Portal übermittle, in jenem Portal falsch dargestellt werden (Unicode! Rocket Science!!). Außerdem erschließt sich mir die Möglichkeit der Übertragung von Textinhalten nicht. Hier gibt die API ein Listenelement vor, mit dem ich mehrere Texte in verschiedenen Sprachen übergeben kann, jeweils klassifiziert durch eine Eigenschaft „language“. Dokumentation und XML-Schema sagen, das sei ein String. Ob ich da nun „Deutsch“, „German“, „de“, „de_DE“ oder was auch immer reinschreiben muss, und analog, was für die englischsprachige Variante dort hin muss. Und ich stelle fest: Von allen übermittelten Textblöcken erscheint immer nur der letzte im Portal – das dann aber unabhängig davon, welche Sprache er hat. Last but not least frage ich zum zweiten Mal nach einem Beispielrequest für das Anlegen einer Unterkunft, der dann vielleicht auch gewisse Anhaltspunkte gibt, was man in diesem oder jenem Element so übermitteln müsste. Die Dokumentation ist da nämlich ziemlich, äh, mau.

Eine weitere Woche geht ins Land. Das mit den Umlauten habe man behoben, teilt man mir mit. Zur WSDL-Datei weiß man überraschend zu sagen, dass „eine Aktualisierung zur Zeit nicht geplant sei“. Ähm – sie ist falsch, aber eine Aktualisierung ist nicht geplant? Na vielen Dank auch. In Sachen Textfeld weiß ich nun, dass hier „de“ erwartet wird – erfahre aber auch gleich, dass die Übermittlung von Texten in mehreren Sprachen derzeit nur in Planung ist, ergo gar nicht funktioniert. Und Beispiele gebe man „eigentlich“ nicht raus, „da die relevanten Informationen in der Dokumentation beschrieben sind und die Umsetzungen in der Praxis sehr unterschiedlich ausfallen können“. Ich staune und interpretiere das als Bitte, mich dann eben bei jeder weiteren Kleinigkeit, bei der ich nicht unbedingt einfach nur raten will, was denn die API erwartet (weil die Dokumentation dazu eben so gut wie nichts enthält), dann eben den Support zu nerven. Zudem frage ich mich, was dieses „eigentlich“ zu bedeuten hat. Hinter einem „eigentlich“ erwarte ich eigentlich (haha) so etwas wie „… aber für Sie mache ich mal eine Ausnahme“. Macht man aber nicht. Das Beispiel bleibt aus.

In puncto „Angabe der Sprache“ gab man mir nebenbei recht – man habe die Dokumentation entsprechend überarbeitet, und mir wurde eine „aktualisierte Version“ zugeschickt. Die aktualisierte Version enthält nun tatsächlich einen entsprechenden Hinweis – während die auf dem Titel genannte Versionsnummer aber identisch zur vorherigen ist, ebenso hat sich die Datumsangabe nicht verändert, und die Dokumenthistorie, die ein separates Kapitel darstellt, weiß auch nichts von diesem überraschenden neuen Release der Dokumentation.

Der nächste Tag bricht an.

Ich arbeite weiter und führe mir die API-Funktion zu Gemüte, mit der ich mir die Eigenschaften von Unterkünften und Zimmertypen abrufen kann. Diese Eigenschaften können nämlich im Sinne einer ordentlichen Kategorisierung nicht als Freitext, sondern nur als numerische Felder übergeben werden – okay, kann ich verstehen. Worüber ich mich nur wundere: Alle Umlaute sind kaputt. Ja, was zum … nun, nachdem ich zur Sicherheit einen tcpdump des HTTP-Datenstroms gemacht habe, ist definitiv klar: Das ist nicht meine Schuld. Die API selbst liefert die Umlaute als vier Bytes – klarer Fall von „doppelt kodiert“. Unicode! Rocket Science!! Aber das ist noch nicht alles. Die Funktion, die mir die Eigenschaften zurückliefert, schmeißt nämlich munter am Ende immer noch ein leeres Eigenschafts-Element mit raus (was laut XML-Schema nicht leer sein darf, weil alle Child-Elemente mandatory sind) und verpasst diesem und dem vorletzten Element noch XML-Attribute, die im XML-Schema überhaupt nicht vorkommen. Soll heißen: Was mir die API zurückliefert, validiert nicht gegen das eigene XML-Schema des Anbieters. Ich baue also einen Filter ein, der ungültige Eigenschaften und leere Elemente rausfiltert, und baue ein zusätzliches decode_utf8 mit ein, um der doppelten Umlautkodierung Herr zu werden. Und, natürlich, ich frage den Support.

Unabhängig von der API eröffnet sich hier das nächste Problemfeld. Auch in der lokalen Datenbank gibt es nämlich Eigenschaften von Unterkünften und Zimmern, und auch hier werden diese durch Mappings zwischen ID und Beschreibung hergestellt. Für die letztlich benötigte Zuordnung von ID zu ID muss ich also anhand der Beschreibung matchen – und schon ein schneller Blick verrät: Was hier ein „Aufzug“ ist, ist dort ein „Lift“. Was hier „Haustiere“ sind, heißt dort „haustierfreundlich“. Bei einigen hundert möglichen Eigenschaften zeichnet sich jetzt schon ab, dass nicht unerhebliche Zeit nicht nur fürs Programmieren, sondern auch für das manuelle Mappen inhaltsgleicher Eigenschaften draufgehen wird. Ich freu mich. Ein Mitarbeiter meines Kunden schreibt flugs ein kleines Webinterface und übernimmt dankenswerterweise das Begriffs-Mapping. Aber das nur am Rande, während ich auf Antwort auf meine Frage warte, wie ich mit der nicht gegen das eigene Schema validierenden XML-Antwort verfahren soll.

Ich warte über zwei Wochen auf die Rückmeldung, die überzähligen XML-Elemente und -Attribute solle ich doch bitte einfach ignorieren. Warum man unter diesen Maßgaben sich dann überhaupt die Mühe macht, ein XML-Schema zu schreiben, ist mir schleierhaft. Auf meinen Hinweis, dass die API die Eigenschaften entgegen der Dokumentation nicht in UTF-8 liefert, sondern in fälschlicherweise doppelter Kodierung, wird nicht eingegangen. Das Problem ist auch heute – Wochen später – nicht behoben.

Beim Mapping der Eigenschaften stellt sich heraus, dass einige wichtige Eigenschaften fehlen, und mein Kunde bittet den Anbieter, diese in seiner Eigenschaftsliste nachzupflegen. Wieso, heißt es da – die sind doch da. „Ich hab’s grad probiert“. Ich teste selbst erneut. Die Eigenschaften sind nicht da. Ins Blaue hinein starte ich diese Read-Only-Abfrage auf dem Produktivsystem und stelle überrascht fest: Hossa! Das Produktivsystem des Anbieters kennt viel mehr Eigenschaften als das Entwicklungssystem … darunter auch die benötigte. Ich baue in mein Tool eine Funktion ein, die das Lesen der Eigenschaftslisten auf dem Produktivsystem macht, das Hinzufügen, Ändern und Löschen von Unterkünften aber auf dem Testsystem, denn davon, die API produktiv zu nutzen, sind wir noch weit entfernt.

Nachdem ich die Eigenschaftsliste vom Produktivsystem abgefragt habe, aktualisiere ich meine Mappings und starte einen erneuten Durchlauf. Was zum..?! Nun sind im Portal wieder Umlaute kaputt, aber nur bei den Eigenschaften, nicht bei den sonstigen Daten einer Unterkunft. Und sie sind anders kaputt – statt doppelt kodiert sind sie nun sozusagen „halb kodiert“. Ich stelle entsetzt fest, dass das Produktivsystem die Umlaute korrekt zurückliefert – ganz im Gegensatz zum Testsystem, für das ich extra das zusätzliche decode_utf8 eingebunden hatte. Also baue ich das wieder aus, denn die Eigenschaftsliste werde ich ja sowieso nie wieder vom Testsystem abrufen, weil die ja unvollständig ist. Als ich mir testweise den HTTP-Trace vom Produktivsystem anschaue, stelle ich fest, dass der Unterkunftstyp „Hütte“ gleich doppelt vorhanden ist, mit zwei verschiedenen IDs. Mit einem fixen SQL-Statement finde ich auch gleich noch weitere Redundanzen. Das kann ja heiter werden.

Derweil beschäftige ich mich mit der Funktion der Zimmertypen. So, wie ich eine komplette Unterkunft mit Hilfe der Update-Funktion anhand der ID, die ich beim Insert zurückbekommen habe, aktualisieren kann, so kann ich auch die Zimmertypen einer Unterkunft aktualisieren. Ich kann aber auch nur das. Das Entfernen von Zimmertypen ist schlicht nicht vorgesehen. Ich kann zwar Zimmertypen hinzufügen; das geht wohl – dabei erfahre ich aber nicht die vom API-System vergebene ID für jenen Zimmertyp. Den gibt’s laut Spezifikation nämlich nur beim Insert einer Unterkunft; da werden dann die IDs der mit übermittelten Zimmertypen gleich mitgeliefert. Mache ich später jedoch ein Update auf eine Unterkunft, ist das nicht der Fall. Soll heißen: Ich bekomme einen zusätzlichen Zimmertypen zwar ins System. Ich kann ihn dann anschließend aber nie wieder ändern – weil ich ja seine ID nie erfahre. Löschen geht genausowenig. Weder mit noch ohne ID. Die Zimmertypenliste ist append only. Wer bitte denkt sich sowas aus?

Die einzige Möglichkeit, die Liste der Zimmertypen nachträglich zu verändern (also nicht die Eigenschaften der Zimmertypen, sondern eben das Hinzufügen oder Entfernen von Zimmertypen) ist insofern, die komplette Unterkunft zu löschen und neu anzulegen. Klar, das geht. Aber …

So eine Unterkunft kann auch Bilder haben. Für diese Bilder übermittele ich entsprechende URLs. Diese werden dann aber nicht etwa im Portal einfach „as is“ eingebunden, sondern das Portal ruft die Bild-URLs ab und speichert diese lokal auf dem Portal-Webserver. Synchron. Synchron heißt: Wenn ein Hotel es nun wirklich gut meint und fünf Außenansichten, fünf Innenansichten und für jeden der vier Zimmertypen noch fünf Innenansichten von Zimmern bereitstellt, dann haben wir 30 Bilder – und mein API-Aufruf mit dem Insert oder dem Update muss warten, bis der Portal-Webserver alle diese Bilder heruntergeladen hat. Na, die werden sich freuen, wenn wir erstmalig die ersten paar hundert Unterkünfte, alle jeweils mit Fotos, in deren System einpflegen … hoffentlich haben die dann Traffic flat.

Kann man die Verarbeitung von Bildern in einer API noch ineffizienter gestalten? Aber sicher, da geht noch was. Sobald die Bilder nämlich abgerufen sind, vergisst die API die Original-URLs. Wenn ich also zu einem späteren Zeitpunkt eine Unterkunft erneut übermittle, zum Beispiel, weil sich die Telefonnummer geändert hat, dann werden alle verknüpften Bilder erneut vom Quellsystem abgerufen. Wenigstens ein „If-Modified-Since“ hätte es doch vielleicht sein dürfen, aber … Fehlanzeige.

Durch Trial and Error finde ich heraus, dass man beim Aktualisieren der Unterkunft offenbar nicht alle Elemente mitschicken muss und das Weglassen eines Elements im Fall der Bilder dafür sorgt, dass die bestehende Bilderliste unverändert bleibt – also die Bilder auch nicht erneut abgerufen werden müssen. Das ist ja schon mal etwas. Im Gegensatz zur Liste der Zimmertypen ist die Liste der Bilder aber nicht append only – übermittle ich hier ein neues Bild, ersetzt das komplett die bisherige Bilderliste. Möchte ich also 30 Bilder um ein Bild Nr. 31 ergänzen, muss ich folglich dann doch wieder alle 31 Bilder übermitteln – die dann auch alle 31 erneut abgerufen werden. Das Übermitteln einer leeren Bilderliste (wo also das XML-Element nicht weggelassen wird, sondern schlicht ohne Child-Elemente übermittelt wird), führt dann überraschenderweise aber nicht zum Löschen aller bestehenden Bilder. Es gilt also: Eine Unterkunft, die einmal Bilder hatte, kann nie wieder gar keine Bilder mehr haben. Mindestens eins muss es dann schon bleiben. Gerade im Hinblick darauf, wie sich die API in Bezug auf die Zimmertypen verhält, fehlt mir hier jegliche Berechenbarkeit. Unnötig anzumerken, dass die Dokumentation mit keiner Silbe Bezug auf die unterschiedliche Handhabung dieser beiden Listen nimmt.

Nun versuche ich heute abend, mit einem dicken Bündel Workarounds und jeder Menge Klimmzüge weiterzuarbeiten. Ich starte damit, nach dem heutigen Support-Mailverkehr zunächst die Kategorieliste zu aktualisieren und wundere mich darüber, dass genau null Kategorien gefunden wurden. In einer zweiten Konsole habe ich den tcpdump-Aufruf für den HTTP-Trace noch griffbereit. Überraschung: Während das Testsystem weiterhin eine unvollständige Liste von Eigenschaften mit fehlerhaften Umlauten liefert, liefert das Produktivsystem nun gar keine Liste von Eigenschaften mehr. Der API-Key wird akzeptiert (ein bewusst falsch gesetzter API-Key provoziert korrekt einen SOAP-Fault), aber das Listenelement in der Antwort ist leer.

Die ursprüngliche Implementierung hatte ich gegenüber dem Kunden mit ca. 6-8 Stunden Umsetzungsdauer angegeben. Inzwischen zieht sich das Projekt seit Wochen hin, was nicht zuletzt dem Umstand geschuldet ist, dass der Support des API-Anbieters wiederholt extrem lange braucht, selbst sauberst mit HTTP-Traces dokumentierte Probleme auf dem Niveau von „Also, bei mir geht’s …“ zu beanworten und offensichtliche Fehler, die auch nichts mit fehlerhafter Bedienung oder schlechter Dokumentation zu tun haben, einfach überhaupt nicht zu fixen. Möglicherweise um den anderen API-Nutzern, die hierfür schon jeweils eigene Workarounds gebaut haben, nicht ihre Systeme kaputtzumachen.

6-8 Stunden also. Veranschlagt. Die realen Stunden belaufen sich entsprechend meiner Arbeitsprotokolle mittlerweile auf 15 – das Verfassen dieses Blogposts selbstverständlich nicht mit eingerechnet. Den gibt’s gratis obendrauf.

Mein persönlicher Rat? Wenn der Begriff „SOAP“ fällt – lauft. Lauft, so weit ihr könnt. Nicht nur, weil das Protokoll den krudesten API-Standard darstellt, der mir in den letzten Jahren untergekommen ist (wobei, nein, da muss ich mich korrigieren – dieser Preis gebührt wohl UCP, mit dem ich für einen anderen Kunden den Versand von SMS implementieren durfte), sondern auch, weil der Einsatz von SOAP nach meiner Erfahrung schon fast als Garant dafür anzusehen ist, dass man es auf der gegenüberliegenden Seite mit Leuten zu tun hat, die sich der Tragweite der Protokollwahl nicht im Geringsten bewusst sind.

Tags: ,

8 Antworten zu “Only use SOAP to wash your hands”

  1. levudev sagt:

    omg… Was mich aber überrascht hat ist, dass du nur 15 Stunden insgesamt gebraucht hast :)

  2. Jonas Pasche sagt:

    Ich tippe schnell ;-)

  3. Scytale sagt:

    Fairerweise muss man aber sagen, dass ein Großteil der Probleme, die du beschreibst, nicht auf den Einsatz von SOAP zurückzuführen ist. Und SOAP ist auch nicht immer ein Anzeichen für Inkompetenz. Das Zeug kommt einfach aus der Businesswelt, die aus Java, .Net und XML besteht. Ein Teil der APIs dort ist sehr gut designed und dokumentiert.

    Die meisten APIs sind allerdings ziemlicher Murks. Als Webentwickler hab ich tagtäglich mit allen Sorten von APIs zu tun. Auffallend ist dabei vor allem eins: Öffentliche APIs (z.B. von Web-2.0-Sites etc.) sind meist wesentlich besser als geschlossene B2B-Dinger. Das liegt wahrscheinlich daran, dass man bei öffentlichen APIs nen Ruf zu verlieren hat. Proprietäre sieht nur der arme API-Coder, der sich damit rumschlagen muss. Sei froh, dass man keinen NDA abverlangt hat, bevor du die Doku lesen durftest. Alles schon erlebt.

    Meine Lieblings-API ist übrigens die, die bei der Übermittlung einer Adresse in Frankreich reproduzierbar eine Tomcat-„Uncaught-Exception“-Seite geschmissen hat. Stellte sich raus, es lag am Singlequote in „Rue d’Alsace“. Was das bedeutet, kannst du dir sicher denken…

  4. Jonas Pasche sagt:

    Um Himmels willen … Little Bobby Tables lässt grüßen.

    Und ich stimme dir zu: Man könnte auch mit SOAP saubere, verlässliche und gut dokumentierte APIs bauen, gar keine Frage. Einige tun das bestimmt auch. Auch wenn mein Rant – der natürlich ohne Frage auch von aktuellem Frust geleitet wurde – das unterschwellig nahelegt: Ich tendiere normalerweise gar nicht so sehr dazu, Dinge aufgrund der Wahl eines bestimmten Protokolls, eines bestimmten Tools oder einer bestimmten Programmiersprache zu verurteilen.

    Diese Unterkunftsgeschichte hier ist aber bei weitem nicht die erste SOAP-API, die zu implementieren ich das Vergnügen hatte, und ich kann so langsam nicht mehr abstreiten, dass sich ein gewisses Muster zeigt: Alle waren schlecht designed, alle hatten schlechte Dokumentation und bei allen hatte ich anbieterseitig mit Leuten zu tun, die völlige Ahnungslosigkeit demonstrierten. Ich meine, wenn ich einen SOAP-Fault mit einem 25-zeiligen Java-Stack-Trace bekomme, der mir in keinster Weise sagt, was dem Server nicht gepasst haben könnte, und die Antwort des Dienstleisters ist dann „ähm, hm, ja, also, probieren Sie doch mal, was passiert, wenn Sie \r\n als Zeilenumbrüche übermitteln“ (was dann nebenbei nicht mehr spezifikationskonform wäre), dann frage ich mich schon, ob man auf Basis einer solchen API wirklich ein Geschäftsmodell aufbauen möchte. Kurz gesagt, es entsteht bei mir mehr und mehr der Eindruck, dass die wirklich fähigen Leute tendentiell eben eher zu anderen Protokollen als ausgerechnet zu SOAP greifen.

    Ich habe hier inzwischen eine ziemliche Abdeckungsskala, am unteren Ende mit beispielsweise einer kleinen regionalen Agentur (wie hier), in der Mitte zum Beispiel mit einem mittelgroßen Mobilfunkunternehmen, deren MMS-API auf Basis von SOAP/MM7 ich umsetzen durfte (das waren die mit dem „probieren Sie doch mal andere Zeilenumbrüche“) bis hin zu richtigen großen APIs wie zum Beispiel der Bürgerportal-Schnittstelle eines Bundeslands, die von T-Systems entwickelt wurde – bisher mein einziges Projekt, bei dem ich ernsthaft in Betracht ziehe, schlicht zu kapitulieren – vor allem, weil der „Support“ hier nur so funktioniert, dass man sich mit seinen Fragen an den zuständigen Sekretär im Ministerium wenden muss, der das dann so gelegentlich mal an T-Systems weitergibt. Aber das ist eine andere Geschichte.

  5. Uli Stärk sagt:

    Das WSDL ist doch der Traum eines jeden Programmiereres (solange man die WSDL-Datei nicht von Hand schreiben muss). Lade die Datei runter und du hast eine ausreichende technische definiertion der Schnittstelle. Wenn das WSDL passt, ist alles weitere ein Kinderspiel. Der Aufruf sieht dann aus wie ein lokaler Funktionsaufruf und ist in zwei Zeilen gemacht, ohne auch nur eine Klasse zu implementieren:
    $client = new soapclient();
    $result = $client->doSendSms($param1, $param2, …);

    Das Error-Handling ist auch gleich mit drin.

  6. Jonas Pasche sagt:

    Das ist im Prinzip völlig richtig. Nur beinhaltet die WSDL-Datei aber schon mal einen falschen Endpoint. Die zurückgelieferten Daten validieren nicht gegen das in der WSDL-Datei referenzierte Schema. Die Umlaute sind falsch kodiert. Das Error-Handling sieht so aus, dass unter diversen Umstanden die API nicht ordentlich HTTP 200 und einen SOAP-Fault zurückliefert, sondern einen Internal Server Error, mit dem die SOAP-Library dann so gar nichts anzufangen weiß. Und last but not least: Egal welches Protokoll man wählt; selbst das tollste Protokoll macht eine schlecht designte API in irgendeiner Art und Weise besser, und schon gar nicht den Support des API-Anbieters … :-)

  7. damage sagt:

    Hi,
    tjo, schon blöd wenn die WSDL nicht zur API paßt. Kann man sich das sparen, da hast du recht.

    Falls du mal SOAP im Bezug auf Alcatel oder Cisco hörst: Da ist bis jetzt alles prima :)

    Gruß
    Daniel

  8. Rolf sagt:

    http://rolfrost.de/xml.html
    http://rolfrost.de/oop.html

    Viel Spaß damit


Impressum