Zum Inhalt springen
DedicatedPHP Kontakt

Vertragstests für PHP-APIs ohne Integrationen zu brechen

Erfahren Sie, wie Sie überprüfbare Verträge definieren und automatisieren, um PHP-APIs weiterzuentwickeln, ohne Inkompatibilitäten erst nach der Bereitstellung zu entdecken.

Redaktionelles Diagramm einer PHP-API, die vor der Bereitstellung Verträge für Anfragen und Antworten validiert

Eine API wird nicht allein durch ihren PHP-Controller oder eine veröffentlichte Spezifikation definiert. Sie wird auch durch die Erwartungen definiert, die andere Systeme bereits übernommen haben: eine Route, der Name eines Feldes, ein HTTP-Statuscode, das Format eines Fehlers oder die erforderliche Reihenfolge zum Durchblättern von Seiten. Vertragstests für PHP-APIs machen diese Erwartungen zu automatisierten Prüfungen, bevor Code zusammengeführt oder bereitgestellt wird.

Das Ziel ist nicht, jede Weiterentwicklung zu verhindern. Es geht darum zu erkennen, ob eine Änderung eine für einen Konsumenten beobachtbare Vereinbarung verändert, und bewusst zu entscheiden: Kompatibilität beibehalten, einen Übergang einführen oder die Schnittstelle versionieren. Das ist besonders wichtig bei internen APIs mit mehreren Teams, B2B-Integrationen und asynchronen Abläufen, bei denen der Fehler erst Stunden nach der Veröffentlichung auftreten kann.

Was Vertragstests lösen und was sie nicht ersetzen

Was Vertragstests lösen und was sie nicht ersetzen — guía visual de DedicatedPHP

Ein Vertragstest prüft, dass Anbieter und Konsument bei einer Interaktion übereinstimmen: Bei einer gültigen Anfrage erzeugt der Anbieter eine Antwort mit einer vereinbarten Struktur, vereinbarten Typen und Regeln. Umgekehrt kann ein Konsument erklären, welche Anfragen er benötigt, und der Anbieter prüft, dass er sie bedienen kann.

Dieser Ansatz erkennt Inkompatibilitäten, die Unit-Tests häufig übersehen. Ein Unit-Test kann bestätigen, dass ein Serialisierer customer_id zurückgibt; er beweist nicht, dass der Konsument dieses Feld weiterhin versteht, wenn er zuvor customerId erwartet hat. Ein lokaler Integrationstest kann die API-Route abdecken, erfasst aber nicht unbedingt die tatsächlichen Annahmen jeder Integration.

Sie ersetzen keine anderen Kontrollen:

  • Unit-Tests, für Domänenregeln, Validierung und Transformationen.
  • Integrationstests, für Datenbank, Warteschlangen, Cache, Authentifizierung oder angebundene Dienste.
  • End-to-End-Tests, für vollständige kritische Abläufe in kontrollierten Umgebungen.
  • Sicherheits- und Leistungstests, für Autorisierung, Missbrauch, Datenoffenlegung, Latenz und Kapazität.
  • Beobachtbarkeit in der Produktion, um Konsumenten zu erkennen, die weiterhin Verhaltensweisen verwenden, die eingestellt werden sollen.

Ein Vertrag bestätigt auch nicht, dass die Antwort fachlich korrekt ist; er bestätigt, dass sie die deklarierte Form und Semantik beibehält. Deshalb muss er durch Beispiele ergänzt werden, die relevante Regeln ausdrücken, nicht nur durch leere Schemata.

Was zum Vertrag einer API gehört

Der Vertrag umfasst jedes Verhalten, das ein Konsument beobachten kann und von dem er abhängt. Ihn auf das JSON einer erfolgreichen Antwort zu beschränken, lässt die häufigsten Brüche außen vor. Für jede Operation sollten mindestens die folgenden Elemente vereinbart werden.

  • Anfrage: Methode, Route, Abfrageparameter, Kopfzeilen, Anfragekörper, Pflichtfelder, Formate und Grenzen.
  • Antwort: HTTP-Statuscode, relevante Kopfzeilen, Struktur, Typen, optionale Felder, Felder, die Nullwerte zulassen, sowie Formate für Datum, Währung oder Identifikatoren.
  • Fehler: Statuscodes, Fehlerkörper, stabiler fachlicher Code und die Bedingungen, die ihn erzeugen. Ein Text für Menschen kann sich ändern; ein Code wie validation_failed eignet sich besser für Automatisierung.
  • Paginierung und Filterung: Bedeutung von limit, Cursor oder Seite, Stabilität der Reihenfolge, Darstellung des nächsten Cursors und Behandlung leerer Mengen.
  • Authentifizierung und Autorisierung: zulässiger Mechanismus, erforderliche Kopfzeilen, Bereiche oder Berechtigungen sowie der Unterschied zwischen ungültigen Zugangsdaten, fehlenden Zugangsdaten und verweigertem Zugriff.
  • Ereignisse und Webhooks: Ereignisname, Version oder Schema der Nutzdaten, Signatur, Wiederholungen, Ereignisidentifikator, nicht garantierte Reihenfolge und Erwartungen an Idempotenz.

Ob eine Eigenschaft verpflichtend ist und ob null zulässig ist, sind unabhängige Regeln. Ein Feld kann verpflichtend sein und null zulassen, optional sein und es bei seinem Auftreten nicht zulassen oder optional sein und es zulassen, wenn es vorhanden ist. Ebenso sind eine ausgelassene Eigenschaft, eine vorhandene Eigenschaft mit null und eine Eigenschaft mit leerer Zeichenkette unterschiedliche Zustände. Wenn der Konsument sie unterschiedlich interpretiert, muss der Vertrag dies ausdrücken und testen.

Kleine Änderungen, die Konsumenten beeinträchtigen können

Eine Änderung kann aus Sicht des Anbieters harmlos erscheinen und für einen generierten Client, einen strikten Validator oder eine Geschäftslogik inkompatibel sein. Einen Integer in eine Zeichenkette zu ändern, etwa 42 in "42", bricht Vergleiche und Schemata. Ein Feld optional zu machen, bestimmt nicht automatisch, ob es null akzeptiert: Die erste Regel definiert, ob die Eigenschaft vorhanden sein muss, während die zweite die gültigen Werte bestimmt, wenn sie enthalten ist.

Weitere riskante Änderungen sind, 200 zurückzugeben, wo zuvor 201 zurückgegeben wurde, eine leere Liste durch null zu ersetzen, die Genauigkeit einer Dezimalzahl zu ändern, einen Fehlercode umzubenennen oder die Paginierungsreihenfolge ohne Ankündigung zu ändern. Ein Feld hinzuzufügen ist für tolerante Empfänger meist kompatibel, aber nicht, wenn ein Konsument ein geschlossenes Schema validiert oder Signaturen über den vollständigen Antwortkörper berechnet.

Kompatibilität hängt von der tatsächlichen Vereinbarung ab, nicht von einer isolierten Regel. Es empfiehlt sich, jede Änderung nach bekannten Konsumenten, deklarierter Toleranz und Kritikalität des Ablaufs zu klassifizieren. Wenn diese Informationen nicht bekannt sind, muss dies als Risiko und nicht als günstige Annahme behandelt werden.

Zwischen Spezifikation, konsumentengesteuerten Verträgen oder beidem wählen

Eine Schnittstellenspezifikation, beispielsweise eine OpenAPI-Beschreibung, eignet sich gut als gemeinsame Quelle für Routen, Operationen, Parameter, Schemata und Antworten. Sie kann in der Pipeline validiert werden, um inkompatible Änderungen gegenüber einer Referenzversion zu erkennen. Sie ist nützlich, wenn es viele Konsumenten gibt oder Clients und Dokumentation aus derselben Definition generiert werden.

Ein Schema erfasst jedoch nicht immer, was für jeden Konsumenten wichtig ist: Kombinationen von Filtern, einen bestimmten Fehler bei einer Geschäftsbedingung oder eine Abhängigkeit von einem Beispielwert. Konsumentengesteuerte Verträge deklarieren konkrete Interaktionen, die jeder Konsument benötigt. Der Anbieter prüft sie gegen seine Implementierung.

Beide Ebenen zu verwenden, ist häufig sinnvoll: Die Spezifikation steuert die allgemeine Oberfläche, und konsumentengesteuerte Verträge decken Abläufe mit hohem Wert oder Semantik ab, die sich schwer auf ein Schema reduzieren lässt. Für jedes Artefakt muss es eine klare Verantwortlichkeit geben. Wird eine Spezifikation bei einer Codeänderung nicht aktualisiert, ist sie keine Quelle der Wahrheit mehr, sondern fiktive Dokumentation.

Repräsentative Beispiele und Grenzfälle

Ein Vertragsbeispiel muss in seiner Struktur realistische Daten enthalten, keine Produktionsdaten. Fügen Sie für eine Bestellressource einen Fall mit Elementen hinzu, einen leeren Fall, wenn dieser gültig ist, Identifikatoren im vereinbarten Format und vollständige Datumsangaben mit Zeitzone, wenn dies die Konvention ist. Ergänzen Sie Fälle für verweigerte Autorisierung, fehlgeschlagene Validierung, nicht vorhandene Ressource und die letzte Seite der Paginierung.

Vermeiden Sie es, irrelevante Details festzuschreiben, die sich legitim ändern, etwa einen zufälligen Identifikator, die aktuelle Uhrzeit oder die Reihenfolge von JSON-Eigenschaften. Verwenden Sie präzise Prüfungen für das Stabile und explizite Toleranz für das Variable. Jedes Beispiel muss einen bekannten Bedarf beantworten; eine riesige Sammlung erfundener Antworten erhöht den Wartungsaufwand, ohne das Vertrauen zu steigern.

Schrittweise Implementierung in einer bestehenden PHP-API

Es ist nicht nötig, die gesamte API vollständig zu modellieren, bevor ein Nutzen erzielt wird. Beginnen Sie mit einem Inventar der Konsumenten: interne Anwendungen, B2B-Clients, Batch-Prozesse, mobile Anwendungen, Automatisierungen und Webhook-Empfänger. Erfassen Sie Verantwortliche, Kontaktkanal, verwendete Operation, Kritikalität und Aktualisierungsfähigkeit.

Priorisieren Sie danach API-Routen, die Ressourcen erstellen oder ändern, Benutzer authentifizieren, Finanzprozesse speisen oder Automatisierungen auslösen. Legen Sie über eine überprüfte Spezifikation und Tests gegen eine reproduzierbare Instanz der API eine Baseline des aktuellen Verhaltens der API fest. In PHP muss der Test über die tatsächliche HTTP-Schicht der Anwendung laufen und darf nicht direkt eine Service-Klasse aufrufen: Der Vertrag umfasst Routing, Middleware, Serialisierung und Ausnahmebehandlung.

POST /api/orders
Authorization: Bearer token
Content-Type: application/json

{"items":[{"sku":"ABC-1","quantity":2}]}

201 Created
{"id":"ord_123","status":"pending","items":[...]}

Das vorherige Beispiel ist nur nützlich, wenn es von Regeln begleitet wird: Welche Felder verpflichtend sind, ob id immer eine Zeichenkette ist, welche Fehler die API bei einer ungültigen SKU zurückgibt und ob der Anfangsstatus garantiert ist. Diese Regeln müssen in Prüfbedingungen überführt werden.

Validierung in der kontinuierlichen Integration und vor der Bereitstellung

Die Pipeline muss vor dem Zusammenführen fehlschlagen, wenn die Implementierung genehmigte Verträge nicht erfüllt. Ein praktikabler Ablauf umfasst das Ausführen von Unit-Tests, das Starten kontrollierter Abhängigkeiten, das Starten der PHP-API mit Testkonfiguration sowie die Validierung von Spezifikation, Verträgen des Anbieters und Verträgen repräsentativer Konsumenten. Die Tests müssen isolierte und deterministische Daten verwenden, damit ein Fehler reproduzierbar ist.

Vergleichen Sie bei einer Änderungsanfrage außerdem die vorgeschlagene Spezifikation mit der veröffentlichten Version, um das Entfernen von Routen, verschärfte Anforderungen an die Anwesenheit, Änderungen an der Zulässigkeit von null, Typänderungen und entfernte Antworten hervorzuheben. Die Diagnose muss Operation, Interaktion und verletzte Regel angeben; ein einfacher Schemafehler zwingt zu zu viel Untersuchung.

Führen Sie vor der Bereitstellung dieselbe Suite für das Artefakt aus, das veröffentlicht werden soll, nicht für einen anderen Build. Überwachen Sie nach der Bereitstellung Fehlercodes, von Clients gemeldete Deserialisierungsfehler, die Nutzung von Versionen und Datenverkehr zu veralteten Routen. Die vorherige Validierung reduziert Risiken; sie ersetzt nicht die Bestätigung des Verhaltens unter realem Datenverkehr.

Kompatibilität, Abkündigung und sichere Rücknahme

Kompatibilität, Abkündigung und sichere Rücknahme — guía visual de DedicatedPHP

Wenn eine Änderung nicht kompatibel ist, bevorzugen Sie einen expliziten Übergang. Sie können ein neues Feld hinzufügen und das bisherige beibehalten, eine neue Operation oder Version einführen und ein Datum für die Einstellung kommunizieren, das durch Nutzungssignale gestützt wird. Die Abkündigung ist ein operativer Zeitraum mit Verantwortlichen, Kommunikation und Messung; nicht nur ein Hinweis in der Dokumentation.

Entfernen Sie ein Verhalten nicht, weil eine Frist abgelaufen ist, wenn Sie Konsumenten, die das bisherige Verhalten noch verwenden, nicht identifizieren können oder der Ablauf kritisch ist. Stellen Sie, wenn möglich, kontrollierte Warnungen und Metriken bereit, um alte Nutzung zu lokalisieren, ohne die Antwort zu verändern. Die schrittweise Einführung einer neuen Version ermöglicht es, Fehler zu beobachten und Verträge zu korrigieren, bevor die Änderung ausgeweitet wird.

Die häufigsten Fehler sind, nur erfolgreiche Antworten zu testen, menschliche Nachrichten statt Fehlercodes zu modellieren, anzunehmen, dass alle Clients neue Felder ignorieren, und echte oder repräsentative Konsumenten nicht einzubeziehen. Vertragstests schaffen Wert, wenn sie Vereinbarungen widerspiegeln, die von beiden Seiten gepflegt werden, und als normale Auslieferungsbedingung ausgeführt werden.

Möchten Sie diese Ideen in Ihrem Projekt anwenden?Lass uns über deine PHP-Plattform sprechen.
Verwandten Dienst anzeigen