Writing HTTP clients in PHP

David Buchmann

This is a live streamed presentation. You will automatically follow the presenter and see the slide they're currently on.

Writing HTTP clients
 in PHP

David Buchmann



Márk Sági-Kazár




  • HTTPlug
  • Client Library
  • Symfony Integration


Request / Response

  • HTTP Server: Get request, reply with response.
  • HTTP Client: Send request, get response.


Interfaces for Request & Response

Immutable, withX methods return a copy

$request = new GuzzleHttp\Psr7\Request();
$request = $request





PSR-7 flow

create request

send request

HTTP Message Factory

Interface for message factory

 => decouple from message implementation

$request = $requestFactory->createRequest(



PSR-7 flow

create request

send request

Message Factory


Interface for HTTP clients

 => decouple from client implementation

$response = $client


PSR-7 flow

create request

send request



Simplistic API for the tutorial

Exercise: Simplistic Client


  • In clients/trivial-skeleton/bin/client
  • Bootstrap HTTPlug
  • Create an item (hardcoded content)
  • Then list all existing items



  • Do not couple code to message/client implementation
  • Use guzzle 5 or guzzle 6
  • Or something else
  • Shared libraries: Do not force implementation on user

HTTPlug Plugins

  • Client independent plugin system
  • Only depends on PSR-7 request/response
  • Plugins provided for:
    • authentication
    • caching
    • logging
    • generic header manipulations
    • etc

HTTPlug Asynchronous

  • AsyncClient
  • Returns promise
$promise = $client->sendAsync($request);
    [$this, 'onSuccess'],
    [$this, 'onFailure']

HTTPlug Discovery

  • Find implementation for HTTPlug client, message factory and stream factory implementations
  • Please allow to inject instance!
public function __construct(
    HttpClient $client = null, 
    MessageFactory $messageFactory = null
) {
    $this->client = $client ?:
    $this->messageFactory = $messageFactory ?: 

API Client Library

API client library

  • API over API
  • Custom or exactly the same domain model

API client library + HTTPlug

  • Use HTTP as transport layer
  • Don't force HTTP client implementation
  • If you need plugins, provide a client factory

Transport: HTTP

Serialization: JSON/XML/etc

Error handling (HTTP Status)

Domain model

Error handling (Domain)

How does it work?

Composer in a library

  • Require php-http/client-implementation
    Virtual package provided by all HTTPlug compliant clients
  • Recommended php-http/message factory-implementation
    Virtual package provided by php-http/message
  • Optionally php-http/discovery
  • require-dev e.g. php-http/guzzle6-adapter to test the library

Composer in an application

  • Require a client implementation (e.g. php-http/guzzle6-adapter)
  • Require a message factory implementation (php-http/message)

Exercise 1: Configuration

  • client/library-skeleton:
    • src/HttpClientFactory.php
    • src/TodoClient.php::__construct

Exercise 2: Get methods

  • client/library-skeleton/src/TodoClient.php:
    • getTodo
    • getTodoPage
  • Try using the command bin/get and bin/list

Exercise 3: Modify methods

  • client/library-skeleton/src/TodoClient.php:
    • createTodo
    • updateTodo
    • deleteTodo
  • Try using the commands bin/


What to test?

  • Domain operations
  • Domain exceptions
  • HTTP calls behind operations
  • Domain models

Exercise 1: Test get methods

  • client/library-skeleton/tests/TodoClientTest.php

Exercise 2: Test modify methods

  • client/library-skeleton/tests/TodoClientTest.php
Symfony is a trademark of Fabien Potencier. All rights reserved.

Bundle for Library

  • Configure services
  • Integration code (form types, validation, ...)


  • Configure clients
  • Configure plugins
  • Debug toolbar integration

Exercise 1: Symfony Bundle

  • clients/symfony-skeleton
  • src/Wsc/TodoBundle
    • Resources/config/services.xml
    • DependencyInjection/Configuration.php
    • DependencyInjection/WscTodoExtension.php

Exercise 2: Symfony Application

  • clients/symfony-skeleton
    • src/AppBundle/Controller/DefaultController
    • app/Resources/views/default/*



HTTP factories

  • Upcoming FIG standard for HTTP factories
  • request, response, uri and stream body

$request = $factory->createReques('GET', '/api/user')
    ->withHeader('Authentication', 'Bearer token')


HTTP Client

  • Eventually, the client interface should be FIG standard
  • Guzzle et al could simply implement that interface

API Client Generator

OpenAPI spec to PHP code



  • Can be used as discovery strategy
  • Allows to have your custom client discovered
    "version": "1.0",
    "name": "php-http/guzzle6-adapter",
    "bindings": {
        "04b5a002-71a8-473d-a8df-75671551b84a": {
            "_class": "Puli\\Discovery\\Binding\\ClassBinding",
            "class": "Http\\Adapter\\Guzzle6\\Client",
            "type": "Http\\Client\\HttpClient"

Get help

They already use HTTPlug

Thank you!

We are glad for any feedback!

Thank you!