HTTP Client for SDKs

SDKs

I like using SDKs when I’m creating prototypes. It’s super easy to get started. You copy and paste some code samples, fill in the minimal configuration needed and there you have it: your first response from the service you’re checking out.

In a world where most services have an HTTP API, you also find a lot of SDKs that abstract away the HTTP details like versioning, authentication and pagination.

There are several ways how SDKs can connect to an HTTP interface. Some SDKs come with their own HTTP clients.

They see me rollin’ (my own), they hatin’

Rolling your own has a couple of downsides: the SDK no longer has a single purpose. Many hours are lost creating, maintaining and testing the HTTP client. Once I’ve seen an automated build fail, because the included HTTP client tests failed because httpbin.org was down. Imagine the frustration this brings.

Require an HTTP client package

Some SDKs have a dependency on a pre-existing HTTP client. One of the more popular HTTP clients is GuzzleHTTP.

Imagine the existance of an SDK which uses Guzzle HTTP version 5. Some people will hesitate to install that SDK because they already use Buzz\Browser or Zend\Http\Client and they are perfectly happy with that and don’t want to learn a new interface.

Others will hesitate to install that SDK because they simply can’t without refactoring. You see, they may already have Guzzle HTTP version 4 (or 6) installed. Although the only difference between Guzzle HTTP v4 and v5 is the 'future' option for async requests, you simply cannot install version 4 and version 5 together. Composer simply isn’t capable of that (luckily).

Then what is the solution? Well…

PSR-7 to the rescue!

With PSR-7 (framework interoperable HTTP message interfaces) available, SDKs can now abstract the use of HTTP clients. They can define a HTTP client interface, which use the HTTP message interfaces, and let others build the adapters.

With php-http, one can depend on a virtual package called php-http/adapter-implementation. This will include a HTTP adapter that implements the Http\Adapter\HttpAdapter interface. The most important method of that interface is very simple:

Creating PSR-7 request objects

But this leaves you with the need to create your own PSR-7 compatible Request object, and to construct it.
You could use the guzzle/psr-7 or zendframework/zend-diactoros package.

You don’t like to construct your own messages? php-http has you covered. There’s a very simple Http\Adapter\Client (inside the php-http/adapter-client package) which implements the Http\Client\HttpClient interface.

The client wraps an adapter and can be used like this:

No need to build your own PSR Request object, but it does return you a PSR Response object. Isn’t that easy?

Dependencies

Confused by all the different packages and their dependencies? The following diagram will show you how it all fits together.

The Guzzle adapter package provides an adapter-implementation and also requires the adapter package, because in that package there’s the interface declaration.

The SDK requires an php-http/adapter-implementation, which is a virtual package. In order to be able to install the SDK, an application also needs to specify which adapter (which provides an implementation) it should install. The SDK also depends on the Adapter (plus an psr/http-message-implementation) and/or the Adapter Client, in order to type hint constructor injection.

Note that all arows in the diagram point upwards, this means everything depends on higher level abstractions, not concretions. This proves to be a very good structure.

Who uses php-http

Who uses this? It’s not exactly stable yet. I don’t know any popular package which is using php-http today, but v3 of willdurand/geocoder uses the egeloen/http-adapter package, which is the predecessor of php-http.