Simplified messaging and microservice development with PHP's PSR-7
By George Lawton
The PHP Framework Interop Group recently published the PSR-7 standard. PSR-7 details a set of PHP interfaces for working with HTTP messages and related entities. These include HTTP requests and responses, URIs (which are used with requests), and uploaded file representations.
With frameworks targeting PSR-7, there is a move towards middleware ecosystems.
Matthew Weier O'Phinney, Zend Framework Project Lead
The biggest benefit of PSR-7 is that it will enable the evolution of middleware ecosystems as an alternative to MVC development models, said Matthew Weier O'Phinney, Project Lead, Zend Framework at Zend Technologies (now part of Rogue Wave Software) and editor of the PSR-7 specification. "With frameworks targeting PSR-7, there is a move towards middleware ecosystems, which in many ways eliminate many of the differences between frameworks, and in some ways replace the idea of frameworks."
PSR-7 also promises to make it easier to implement more efficient microservices. O'Phinney said, "With PSR-7, you can write small, targeted APIs with very few dependencies. Typically your dependencies will be PSR-7 itself, a slim middleware framework such as Expressive, and then just the specific dependencies for your application. Since microservices are typically very limited in scope, the code is very terse and succinct, allowing efficient development, and, more importantly, efficient and simplified deployment."
In particular, it also provides a separate ServerRequestInterface, which abstracts functionality commonly found in PHP's superglobals. It also has additional abstractions to fill in gaps in PHP's implementation. It also allows for non-server API implementations such as found in projects like ReactPHP, which provides a way for creating asynchronous PHP-based web applications in a similar fashion to Node.js.
PSR stands for PHP Standards Recommendation, a term purloined from the Java ecosystem's JSR (Java Standards Recommendation). They are a product of the PHP Framework Interop Group, an independent group of PHP framework and library authors who are working to standardize tooling and quality assurance for the PHP ecosystem.
Contrasting JSON, REST and PSR-7
JSON is a serialization format, while REST is architecture for APIs delivered over HTTP. PSR-7 targets the HTTP messages themselves. There are two types of message, a request and a response.
A request looks like this:
POST /path HTTP/1.1 Host: example.com Content-Type: application/x-www-form-urlencoded this=is&data=for&the=payload
The first line is the request line. The first word is the HTTP request method used; in this case, "POST". The second item is the request target, which is usually the path on the server being requested. The third item is the HTTP protocol version (in this case, HTTP/1.1). After that are one or more HTTP headers, which are key value pairs. Finally, an empty line separates headers from the message body.
A response looks similar:
HTTP/1.1 200 OK Content-Type: text/html Success!
The first line of a response is the status line, and contains the HTTP protocol version, a status code, and optionally a "reason phrase" (which HTTP/2 omits) It then is followed by 1 or more header lines, an empty line, and the message body.
Where JSON fits in is the message body; it would be what is sent to an API or returned by an API. REST is how all the pieces work together: using URIs to represent resources, having content negotiation to allow different message payload types (JSON vs. XML, etc.), and structure within the payload for representing links between resources.
O'Phinney said, "Essentially, PSR-7, by modeling HTTP messages, creates a standard way for interacting with the various parts of the message, which enables developers to write framework-agnostic REST tooling. The hope is that we'll see lots of single-purpose libraries that do things like content negotiation, authentication, authorization, etc. that directly target PSR-7, which will allow people to mix-and-match what they need to develop their applications."
Several implementations of PSR-7 exist at this time. Slim Framework is currently in RC status and contains a standalone implementation. Guzzle, an HTTP client, also has one. Symfony has provided integration with PSR-7 since their 2.7 release in May. Zend has shipped one since PSR-7 went stable, called Diactoros, and this implementation is the most widely-used one in the PHP ecosystem today.
PSR-7 is still in the early phases of adoption, so there are not many API management tools that are targeting it. Zend plans to rewrite the Apigility API Engine and Builder around PSR-7 and middleware with an upcoming version 2, which it hopes to preview in Q1 2016.
Since PSR-7 is simply a set of interfaces, it works well with existing unit testing frameworks, said O'Phinney. This also means that developers can often simply mock the interfaces, instead of having concrete implementations, when testing. This simplifies testing tremendously, and provides a uniform interface to test against.
Best practices for implementing PSR-7 into applications
One of the best practices is to use middleware to implement PSR-7, said O'Phinney. Additionally he recommends that the middleware accept the request, response, and a function allowing invocation of the next middleware in the call stack:
function (ServerRequestInterface $request, ResponseInterface $response, callable $next) : ResponseInterface
This reduces the dependencies required. Developers can code to the interface abstractions versus using concrete implementations. It also shifts from a convention-over-configuration approach to a functional paradigm.
Role in Moving from MVCs to Middleware
Zend internal benchmarks have shown PSR-7-based middleware applications as performing at speeds 400% faster than equivalent functionality in traditional full-stack MVC frameworks. These applications also use a small fraction of the CPU and memory.
O'Phinney believes middleware-based strategies will perform better than traditional full-stack MVC frameworks. The flip-side, however, is that most current middleware-based applications will require that developers to create their own architecture in terms of class and file placement. This has ramifications when on-boarding new developers, since it is difficult to point to a specific set of practices for where to find the code as with an MVC framework. This is something Zend is aiming to address with initiatives such as Expressive.
MVC frameworks usually provide a lot of structure out of the box, with a lot of wiring to ensure everything works together smoothly. This makes them very useful particularly for starting projects, as they eliminate the need to create an architecture from scratch. The flip side is that those features and the wiring come at a cost to performance.
O'Phinney said, "I tend to think of MVC frameworks as promoting developer experience and productivity over application performance. In order to squeeze performance out of an MVC framework, you will typically need to put effort into caching, and may want to look into caching proxy servers such as varnish to ensure that the application scales as the code base grows."
Middleware microframeworks tend to promote rapid application development and ease of use, as well as performance. However, they typically do not usually scale the architecture well, which means developers will need to make decisions about structure as the application expands.
O'Phinney said, "I tend to think of middleware microframeworks as assisting the first steps and performance, at the expense of long-term maintenance. You will need to look into how to scale the architecture to ensure the maintenance story is clear long-term. We are making some serious efforts to address the long-term maintenance story with Expressive, by providing guidance on application structure to help application maintenance scale long-term."
Going forward, O'Phinney expects to see frameworks moving towards accommodating PSR-7 initially, and eventually envision that traditional full-stack MVC usage will be replaced by middleware. Using middleware call-stacks allows composable applications built of small, single-purpose code targeting PSR-7. Composing middleware then allows for complex interactions and behavior.
How does microservice development in PHP compare with Java? Let us know.
03 Jan 2016