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
ZendHttpClient 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.
Like this someone can build a Guzzle 5 adapter package, a Guzzle 6 adapter package, a Zend adapter package, a Cake adapter package, …
Sounds great? Let me tell you this: it’s already been done. It’s called php-http!
With php-http, one can depend on a virtual package called
php-http/adapter-implementation. This will include a HTTP adapter that implements the
HttpAdapterHttpAdapter 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
You don’t like to construct your own messages?
php-http has you covered. There’s a very simple
HttpAdapterClient (inside the
php-http/adapter-client package) which implements the
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?
Confused by all the different packages and their dependencies?
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.
Want to play around with PSR-7?
Other handy resources
- Getter, Setter, Never!
- How we improved our PWA score
- Use gitattributes to keep your commits clean
- Hexagonal Architecture demystified
- Integrating Elasticsearch with your Laravel App
- Laravel IoC Container