Black Friday: 30 % Rabatt auf alle Trainings und 10 % Rabatt auf alle Dienstleistungen Hol dir ein Angebot


Lass die Nutzer des SDK ihren eigenen HTTP-Client nutzen

· Mathieu Santostefano · 5 Minuten zum Lesen
3 dog heads

Befreie dich von starren Abhängigkeiten in deinen PHP-SDKs. Erfahre, wie du die Standards PSR-7, PSR-17 und PSR-18 zusammen mit PHP-HTTP/Discovery nutzt, um deinen Benutzern die Verwendung ihres bevorzugten HTTP-Clients zu ermöglichen – sei es Guzzle, Symfony HttpClient oder ein anderes Tool. Ein Muss für PHP- und Symfony-Entwickler.

Dieser Artikel behandelt praktische Techniken für SDK-Entwickler, die es Benutzern ermöglichen, ihren eigenen HTTP-Client zu verwenden, statt ihnen die Nutzung eines Clients aufzuzwingen, den sie nicht gewählt haben. Er richtet sich auch an Benutzer, die ihren bevorzugten HTTP-Client innerhalb eines SDKs verwenden möchten, das diesen bereits unterstützt.

Du kennst wahrscheinlich den Dschungel der HTTP-Clients, die im PHP-Ökosystem existieren. Guzzle, Symfony HttpClient, Buzz, CakePHP HTTP usw. Als SDK-Maintainer ist es ein Albtraum, Support für all diese Pakete bereitzustellen. Glücklicherweise gibt es Abstraktionsschichten und Techniken, die uns dabei helfen, die große Mehrheit davon zu berücksichtigen. Lass uns gemeinsam herausfinden, wie das funktioniert!

Genesis

Vor ein paar Monaten besuchte ich den AFUP Day 2025, eine eintägige französische Konferenz. Insbesondere besuchte ich einen Vortrag meines Freundes Nicolas Grekas über HTTP-Clients in PHP. Der Vortrag war nicht ganz so, wie ich ihn mir vorgestellt hatte. Er versetzte das Publikum in die Lage eines SDK-Entwicklers, der vor der Herausforderung steht, einen HTTP-Client in seine Quellcode-Abhängigkeiten zu integrieren.

  • Welchen HTTP-Client?

  • Was, wenn ein SDK-Benutzer bereits einen HTTP-Client in seinen Abhängigkeiten installiert hat?

  • Wie kann ein SDK-Benutzer seinen eigenen HTTP-Client anstelle des von mir bereitgestellten verwenden?

Die meisten dieser Fragen hat Nicolas auf elegante Weise beantwortet. Lass uns in dieses faszinierende Thema eintauchen!

Hier ist eine Aufzeichnung seines Vortrags von der API Platform Con 2024:

API Platform Conference 2024 - Nicolas Grekas - Consuming HTTP APIs in PHP the Right Way!

Statte dich mit den richtigen Werkzeugen aus

Zunächst möchte ich dir einige PSRs (PHP Standard Recommendations) sowie einige nicht so „magische” PHP-Pakete vorstellen, die uns bei unserer Suche helfen können.

PSR

Zunächst sind hier einige PSRs. Falls du damit nicht vertraut bist, betrachte sie als beliebte technische Empfehlungen für Bibliotheksentwickler und deinen eigenen Anwendungscode. Diese PSRs decken viele Themen ab, z. B. Codierungsstil, Autoloading, Cache, Container, Clock und das, woran wir heute interessiert sind: HTTP.

PSR-7: HTTP Message

Diese beschreibt Schnittstellen für Request und Response (sowie einige „Untertypen“ wie Stream, UploadedFile usw.) und wird von PSR-18 als Argumenttyp und Rückgabetyp für die Methode sendRequest verwendet.

PSR-18: HTTP Client

Diese PSR kann wie folgt zusammengefasst werden: Es wird eine gemeinsame Schnittstelle zum Senden von PSR-7-Anfragen und Zurückgeben von PSR-7-Antworten bereitgestellt.

Sie stellt eine Client-Schnittstelle und drei Exception-Schnittstellen bereit, um verschiedene Arten von Fehlern darzustellen.

PSR-17: HTTP Factories

Diese PSR stellt Factories für alle HTTP-Nachrichtenschnittstellen bereit, die in PSR-7 definiert sind. Wie diese Factories genutzt werden können, sehen wir weiter unten.

PHP-Pakete

PSR/HTTP-Client

Dieses Paket enthält den Code im Zusammenhang mit PSR-18 (ClientInterface und drei Exception-Schnittstellen). Genau das brauchen wir, um unseren Code zu typisieren und uns nicht auf eine konkrete Implementierung zu verlassen.

php-http/discovery

Es handelt sich dabei sowohl um eine Codebibliothek als auch um ein Composer-Plugin (seit Version 1.17). Es ist für die automatische Erkennung und Installation von Paketen zuständig, die konkrete Implementierungen von PSR-17- und PSR-18-Schnittstellen bereitstellen.

Es funktioniert zusammen mit den nächsten beiden Paketen.

psr/http-client-implementation & psr/http-factory-implementation

Diese beiden Pakete sind etwas Besonderes, da es sich um virtuelle Pakete handelt. Sie existieren nur im Packagist-Register und werden von „echten” Paketen verwendet, um anzuzeigen, dass sie konforme Implementierungen für PSR-17- und/oder PSR-18-Schnittstellen bereitstellen.

Ein kurzer Hinweis zum Konzept der virtuellen Pakete: Stelle es dir wie PHP-Interfaces vor, aber auf Paketebene. In diesem Beispiel zeigt das virtuelle Paket psr/http-client-implementation in einer SDK-composer.json an, dass das SDK jedes Paket benötigt, das eine konkrete Implementierung von PSR-18 bereitstellt.

Da „psr/http-client” direkt von „psr/http-message” abhängt, müssen wir nicht davon abhängig sein, um auf Nachrichtenschnittstellen wie RequestInterface, ResponseInterface usw. zu verweisen.

Eine letzte nützliche Eigenschaft ist die provide-Eigenschaft des Composer-Schemas. Hier ist eine konkrete Verwendung dieser Eigenschaft:

  • Maintainer des Pakets symfony/http-client können diese Eigenschaft in die „composer.json”-Datei aufnehmen, um anderen Entwicklern mitzuteilen, dass das Paket eine konkrete PSR-18-Implementierung bereitstellt.

"provide": {
    "psr/http-client-implementation": "1.0",
},
  • Als SDK-Entwickler kannst du das virtuelle Paket psr/http-client-implementation zusammen mit php-http/discovery anfordern. Letzteres sorgt als Plugin dafür, dass das SDK eine PSR-18-Implementierung benötigt. Es wird dann in der composer.json der Anwendung, in der es installiert ist, nach einer suchen, indem es die provide-Eigenschaft jeder Abhängigkeit liest.

  • Ein Bild sagt bekanntlich mehr als tausend Worte. Hier ist eines:

Scheme showing how HTTP client works with PSRsDank PHP-HTTP/HTTP-Discovery, das von Foo/SDK benötigt wird, können die Entwickler beider Anwendungen lediglich ihren bevorzugten HTTP-Client und Foo/SDK anfordern. Die Erkennungsfunktion sucht nach jedem Paket, das von der composer.json der Anwendung benötigt wird und psr/http-client-implementation bereitstellt.

Um die Erklärung zu vereinfachen, lasse ich das virtuelle Paket psr/http-factory-implementation hier bewusst weg, das Prinzip ist jedoch dasselbe.

Bereite deinen Code vor

SDK-Codebeispiel

<?php

use Http\Discovery\Psr17Factory;
use Http\Discovery\Psr18ClientDiscovery;
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamFactoryInterface;
use Psr\Http\Message\StreamInterface;

namespace Foo\SDK;

final readonly class Api
{
    private const string BASE_URI = 'https://example.com';

    public function __construct(
        private ?ClientInterface $client = null,
        private ?RequestFactoryInterface $requestFactory = null,
        private ?StreamFactoryInterface $streamFactory = null,
    ) {
        $this->client = $client ?: Psr18ClientDiscovery::find();

        $this->factory = new Psr17Factory(
            requestFactory: $requestFactory,
            streamFactory: $streamFactory,
        );
    }

    public function callApi(array $data): ResponseInterface
    {
        $body = $this->factory->createStream(json_encode($data));

        $request = $this->factory->createRequest('POST', self::BASE_URI . '/api/bar')
            ->withHeader('Content-Type', 'application/json')
            ->withBody($body)
        ;

        return $this->client->sendRequest($request);
    }
}

Hier ist ein grundlegendes Beispiel einer Foo-Klasse, die von einem SDK bereitgestellt wird und in ihrem eigenen Code PSR-18- sowie PSR-17-Schnittstellen verwendet. Dadurch haben SDK-Benutzer die Freiheit, ihren eigenen HTTP-Client mitzubringen.

  • automatisch, dank Psr18ClientDiscovery::find()

  • oder manuell durch Übergabe eines $client-Arguments an den Konstruktor.

Beachte, dass Psr17Factory intern Psr17FactoryDiscovery-Methoden aufruft, um vorhandene konkrete Implementierungen benötigter Factories zu finden, falls null an den Konstruktor übergeben wird.

Code-Beispiel des Benutzers

<?php

namespace App;

use Symfony\Component\HttpClient\HttpClient;
use Symfony\Component\HttpClient\Psr18Client;

final readonly class FooRelatedService
{
    public function callBar(array $data): void
    {
        // Inside Foo/SDK/Api, Psr18ClientDiscovery will seek for a concrete implementation of PSR-18
        $fooApi = new Foo\SDK\Api();
        $response = $foo->callApi($data);

        // your logic
    }

    public function callBarWithMyOwnHttpClient(array $data): void
    {
        // Standalone instanciation, but dependency injection could be used here.
        $myOwnHttpClient = new Psr18Client(HttpClient::create());

        $fooApi = new Foo\SDK\Api(client: $myOwnHttpClient);
        $response = $foo->callApi($data);

        // your logic
    }

    public function callBarWithMyOwnHttpClientAndFactories(array $data): void
    {
        // Psr18Client implements ClientInterface, RequestFactoryInterface, StreamFactoryInterface and others
        $myOwnHttpClientAndFactories = new Psr18Client(HttpClient::create());

        $fooApi = new Foo\SDK\Api(
            client: $myOwnHttpClientAndFactories,
            requestFactory: $myOwnHttpClientAndFactories
            streamFactory: $myOwnHttpClientAndFactories
        );
        $response = $foo->callApi($data);

        // your logic
    }
}

Es folgt ein einfaches Beispiel für den Code eines SDK-Benutzers. Dabei lässt das SDK den passenden HTTP-Client selbst finden (Methode callBar) oder es wird manuell ein Client übergeben (Methode callBarWithMyOwnHttpClient). Es ist sogar möglich, den Client und die Factories zu übergeben (Methode callBarWithMyOwnHttpClientAndFactories). Bevor du diese Objekte übergibst, kannst du sie selbstverständlich für deine Bedürfnisse konfigurieren (Basis-URI, Header usw.).

Solange das SDK auf Schnittstellen basiert, steht es dem SDK-Benutzer völlig frei, eigene Schnittstellenimplementierungen zu erstellen und diese an das SDK-API-Objekt zu übergeben.

Weiterführende Informationen

Selbstverständlich haben wir hier nur an der Oberfläche des Themas gekratzt. Während der Entwicklung eines SDKs können viele weitere Fragen aufkommen, insbesondere, wenn du dich zu einem bestimmten Zeitpunkt auf eine spezifische Funktion eines HTTP-Clients verlassen musst, die nicht von PSR-18 abgedeckt wird.

Du könntest dich beispielsweise fragen, was passiert, wenn ein SDK-Benutzer keinen kompatiblen HTTP-Client in seinen Anwendungsabhängigkeiten hat. Solltest du standardmäßig einen bereitstellen? Welchen? Wie kann man ihn bereitstellen? Wie testet man als SDK-Maintainer seinen Code?

Wenn dir dieser Artikel gefallen hat und du tiefer in das Thema eintauchen möchtest, lass es uns wissen! Vielleicht folgt ein zweiter Teil, um dieses erste Kapitel zu ergänzen!

Ressourcen

Du möchtest diese Strategie in dein eigenes SDK implementieren, weißt aber nicht, wie du anfangen sollst?

Der Entwickler von Symfony, SensioLabs, bietet spezialisierte Beratung und Schulungen an. Damit unterstützt er Ihr Team dabei, Best Practices für die moderne PHP-Entwicklung und HTTP-Client-Integration zu erlernen.

Das könnte dich auch interessieren

The SensioLabs team celebrating the 20th anniversary of Symfony with balloons
Jules Daunay

Die Geschichte geht weiter: SensioLabs feiert 20 Jahre Symfony

Die Zeit vergeht wie im Flug – besonders, wenn man an der Zukunft der Entwicklung schreibt! Das SensioLabs-Team hat gerade die 20 Kerzen des Symfony-Frameworks ausgeblasen. Wir haben den Anlass im Büro gefeiert, doch die Party ist noch nicht vorbei. Das Datum für eine XXL-Feier steht bereits fest: die SymfonyCon Amsterdam vom 27. bis 28. November 2025.

Mehr erfahren
PHP 8.5 URI extension
Oskar Stark

PHP 8.5's neue URI-Erweiterung: Ein Game-Changer für URL-Parsing

PHP 8.5 führt eine leistungsstarke neue URI-Erweiterung ein, die die URL-Verarbeitung modernisiert. Mit Unterstützung für RFC 3986 und WHATWG-Standards bietet die neue Uri-Klasse unveränderliche Objekte, fluent Interfaces und korrekte Validierung - und behebt alle Einschränkungen der veralteten parse_url()-Funktion. Dieser Leitfaden zeigt praktische Vorher/Nachher-Beispiele und erklärt, wann welcher Standard zu verwenden ist.

Mehr erfahren
Open in new tab
Silas Joisten

Die Tab-Falle: Warum das Erzwingen neuer Tabs eine schlechte UX ist

Wir haben es alle schon getan — target="_blank" zu einem Link hinzugefügt, um „Benutzern zu helfen", auf unserer Website zu bleiben. Aber was sich wie eine harmlose Bequemlichkeit anfühlt, führt oft zu Verwirrung, beeinträchtigt die Barrierefreiheit und birgt versteckte Sicherheitsrisiken.

Mehr erfahren
Blue sign on a building with several Now What? letters
Thibaut Chieux

Wie man Nachrichten beim Aufbau asynchroner Anwendungen mit dem Symfony-Messenger priorisiert

Die asynchrone Verarbeitung bietet Vorteile wie entkoppelte Prozesse und schnellere Reaktionszeiten. Die Verwaltung von Nachrichtenprioritäten kann jedoch zu einer Herausforderung werden. Bei Aufgaben, die vom Zurücksetzen von Passwörtern bis hin zu komplexen Exporten reichen, ist die rechtzeitige Zustellung kritischer Nachrichten unerlässlich. Dieser Artikel befasst sich mit häufigen Problemen bei der asynchronen Verarbeitung und zeigt Lösungen mit Symfony Messenger auf, mit denen Sie Ihre Anwendung ohne umfangreiches Refactoring optimieren können.

Mehr erfahren
SensioLabs University Courses announcing the new level 3 Master training course now available
Jules Daunay

Wir stellen vor: Mastering Symfony 7

Wenn du deine Symfony-Kenntnisse verbessern möchtest, ist der neue Level-3 Trainingskurs bei SensioLabs vielleicht das Richtige für dich! Du meisterst komplexe Themen, optimierst die Leistung und wirst zum Symfony-Experten.

Mehr erfahren
PHP 8.5
Oskar Stark

Was ist neu in PHP 8.5: Ein umfassender Überblick

PHP 8.5 wird im November 2025 veröffentlicht und bringt mehrere nützliche neue Features und Verbesserungen mit sich. Diese Version konzentriert sich auf die Verbesserung der Developer Experience, neue Utility-Funktionen und bessere Debugging-Möglichkeiten.

Mehr erfahren
Two images: on the left many cars stuck in a traffic jam with the sign "All directions" above, on the right a blue car moving forward alone on the highway with the sign "Service Subscriber" and a Symfony logo above
Steven Renaux

Symfony Lazy Services mit Stil – Steigere deine Entwicklererfahrung mit Service Subscribers

Steigere die Performance und Developer Experience (DX) deiner Symfony-App! Erfahre, wie du Service Subscribers und Traits für das verzögerte Laden von Services verwendest, um die sofortige Instanziierung zu reduzieren, Abhängigkeiten zu vereinfachen und modularen, wartbaren Code zu schreiben.

Mehr erfahren
the surface of the earth seen from the space with city lights forming networks
Imen Ezzine

HTTP-Verben: Der ultimative Leitfaden

Hier erklären wir dir die Grundlagen von GET, POST, PUT, DELETE und mehr. In diesem Artikel erfährst du alles über die Funktionsweise, die Anwendungsmöglichkeiten und die Sicherheitsauswirkungen.

Mehr erfahren
Poster of Guillaume Loulier presentation
Salsabile El-Khatouri

Ein Symfony-Training bei SensioLabs: Hinter den Kulissen

Wie sieht die Symfony-Schulung bei SensioLabs aus? Erfahren Sie es im Interview mit Guillaume Loulier, einem leidenschaftlichen Entwickler und Trainer, der uns alles über die offiziellen Symfony-Schulungen erzählt.

Mehr erfahren
Domain Driven Design practical approach
Silas Joisten

Anwendung von Domain-Driven Design in PHP und Symfony: Ein praktischer Leitfaden

Erfahre anhand praktischer Beispiele, wie du die Prinzipien des Domain-Driven Design (DDD) in Symfony anwendest. Entdecke die Leistungsfähigkeit von Value Objects, Repositories und Bounded Contexts.

Mehr erfahren
Photo speaker meetup AI Symfony
Jules Daunay

Symfony und AI: das Video ist jetzt verfügbar

Was ist mit Symfony und Artificial Intelligence (AI)? Dies war das Thema der exklusiven Veranstaltung, die von SensioLabs in Zusammenarbeit mit Codéin am 3. Oktober organisiert wurde. Mit dem zusätzlichen Bonus des Feedbacks aus einem Entwicklungsprojekt, das Symfony und AI kombiniert. Falls du die Veranstaltung verpasst hast, schau dir das Video an, das jetzt kostenlos auf unserem Youtube-Kanal verfügbar ist.

Mehr erfahren
2025 a year of celebrations for PHP with windows about API Platform, PHP, AFUP and Symfony
Jules Daunay

2025: Das Jahr der Jubiläen für PHP, AFUP, Symfony und API Platform

2025 wird ein großes Jubiläumsjahr. Wir feiern 20 Jahre Symfony, 30 Jahre PHP, 25 Jahre AFUP und 10 Jahre API Platform. Für SensioLabs ist dies ein wichtiger Meilenstein, der die Langlebigkeit der Technologien in unserem Ökosystem beweist. Wir sind stolz darauf, diese Jubiläen das ganze Jahr über mit der Community zu feiern.

Mehr erfahren
SymfonyDay Chicago 2025
Simon André

SymfonyDay Chicago 2025: Die Community feiern

Am 17. März traf sich die Symfony-Community in Chicago zum SymfonyDay 2025. Das Event - passend zum St. Patrick’s Day - war nicht nur eine Feier von Symfony, sondern auch ein Moment, um Ryan Weaver in seinem Kampf zu unterstützen. Es war mehr als nur eine Konferenz - es war ein Treffen rund um ein geschätztes Mitglied unserer Community.

Mehr erfahren
Blue ElePHPant on a computer
Imen Ezzine

Optimieren von PHP-Code: 8 Funktionen, die man für die effiziente Manipulation von Tabellen kennen sollte

Um ein hervorragender PHP-Entwickler zu werden, muss man den Umgang mit Tabellen perfekt beherrschen. Diese Strukturen sind in PHP unverzichtbar, sei es, um Daten zwischenzuspeichern, zu organisieren oder zu bearbeiten, bevor sie in einer Datenbank gespeichert werden. Wenn du ihre Funktionsweise beherrschst, wirst du in der Lage sein, deine Informationen effizienter und optimierter zu verwalten und zu manipulieren.

Mehr erfahren
type-safety-uuid
Oskar Stark

Typensichere IDs mit Symfony und Doctrine: Verwendung dedizierter ID-Klassen

Lerne, wie du die Typensicherheit in Symfony und Doctrine durch die Verwendung dedizierter ID-Klassen wie BookId und UserId anstelle roher UUIDs verbessern kannst. Dieser Ansatz verhindert die Verwechslung von IDs, verbessert die Codeklarheit und sorgt für eine bessere Integration mit Symfony Messenger und Repository-Methoden. Entdecke praxisnahe Beispiele und Best Practices zur Implementierung typsicherer IDs in deinen Symfony-Anwendungen.

Mehr erfahren
Image