--- 
canonical: 'https://mwop.net/blog/2016-04-17-react2psr7.html'
title: 'Serve PSR-7 Middleware Via React'
author: "[Matthew Weier O'Phinney](https://mwop.net)"
created: '2016-04-17T15:00:00-05:00'
updated: '2016-04-17T15:00:00-05:00'
tags:
  - async
  - php
  - programming
  - psr-7
  - react

---
I've been intending to play with [React](http://reactphp.org) for some time,
but, for one reason or another, kept putting it off. This past week, I carved
some time finally to experiment with it, and, specifically, to determine if
serving [PSR-7](http://www.php-fig.org/psr/psr-7) middleware was possible.





## React

For those of you unfamiliar with it, React is a project with the goal of
providing event-driven, asynchronous PHP, in a vein similar to
[node.js](https://nodejs.org). To accomplish this, it makes use of one of
several experimental extensions, falling back to PHP's built-in `tick()` support
and stream utilities. The project provides the event loop implementation; a
Promises library; a cross-platform, low-level socket library; an HTTP
server; and several other libraries.

The library that most associate with React, though, is the HTTP server. This
library is in the same vein as node's [HTTP](https://nodejs.org/api/http.html)
module, which provides the low-level plumbing for creating HTTP servers.

A basic server looks like this:

```php
$app = function ($request, $response) {
    $response->writeHead(200, array('Content-Type' => 'text/plain'));
    $response->end("Hello World\n");
};

$loop = React\EventLoop\Factory::create();
$socket = new React\Socket\Server($loop);
$http = new React\Http\Server($socket, $loop);

$http->on('request', $app);
echo "Server running at http://127.0.0.1:1337\n";

$socket->listen(1337);
$loop->run();
```

What I wanted to do was get React to execute PSR-7 middleware, specifically an
[Expressive](https://zendframework.github.io/zend-expressive) application.

## Translating React to PSR-7

React provides its own request and response implementations. As noted, these are
very much aligned with node, down to the level that each is a stream, with
additional methods based on the message type. If you've played with node at all,
React's HTTP layer will feel very familiar.

The problem, though, is that the messages differ from PSR-7; you can't just pass
them into middleware expecting PSR-7 and have everything work. So, a translation
layer was required.

This boiled down to two tasks:

- Marshaling a PSR-7 request instance from the React request.
- Pulling information from the PSR-7 response returned by middleware, and using
  that information to populate and write to the React response.

I discovered quickly that the latest stable release and the current master
branch of react/http differ significantly. In particular, the current master
branch offers a number of new features, such as URL discovery and file upload
handling, which make generating the PSR-7 request far easier. In the end, the
logic becomes something like this:

```php
$body = fopen('php://temp', 'w+');
fwrite($body, $reactRequest->getBody());
fseek($body, 0); // Rewind the stream

return new Zend\Diactoros\ServerRequest(
    $_SERVER,
    $reactRequest->getFiles(),
    $reactRequest->getUrl(),
    $reactRequest->getMethod(),
    $body,
    $reactRequest->getHeaders(),
    [], // cookies; these can be handled by PSR-7 middleware
    $reactRequest->getQuery(),
    $reactRequest->getPost(),
    $reactRequest->getHttpVersion()
);
```

Handling the response can be relatively simple:

```php
$reactResponse->writeHead(
    $psr7Response->getStatusCode(),
    $psr7Response->getHeaders()
);
$reactResponse->end((string) $psr7Response->getBody())
```

That said, I found it was useful to perform a few additional things:

- If no content type is set, set it to `text/html`.
- Rewind the PSR-7 response body before retrieving it. I've occasionally
  observed truncated content otherwise.
- Close the PSR-7 response body when done. This will close the underlying
  resource, freeing up memory.

```php
if (! $psr7Response->hasHeader('Content-Type')) {
    $psr7Response = $psr7Response->withHeader('Content-Type', 'text/html');
}

$reactResponse->writeHead(
    $psr7Response->getStatusCode(),
    $psr7Response->getHeaders()
);

$body = $psr7Response->getBody();
$body->rewind();

$reactResponse->end($body->getContents());
$body->close();
```

I also at one point attempted to iterate through the PSR-7 stream, like this:

```php
while (! $body->eof()) {
    $reactResponse->write($body->read(4096));
}
$reactResponse->end();
```

Unfortunately, this never worked, and led to connection timeouts. If somebody in
the React community wants to edify my as to why (or how I could make it work),
I'd appreciate it!

## Static files

When you create an HTTP server, it's often useful to serve static files: CSS,
JS, images, etc. Out of the box, however, React does not do so.

I tried an approach [using React's filesystem
library](https://blog.wyrihaximus.net/2015/04/reactphp-http/), but had no luck
with it; for some reason, file contents were never returned. As such, I took
another approach entirely, and wrote PSR-7 middleware to serve the files, making
this the outer layer of my middleware so that it executes earliest, and then
delegates to the application middleware when files are not found. I also have
the middleware:

- implement a whitelist, to restrict which files may be served
- match directories to index files (e.g., `index.html`)

```php
$path = $this->root . $request->getUri()->getPath();
if (is_dir($path)) {
    $path = rtrim($path, '/') . '/index.html';
}

if (! preg_match('#\.(?P<type>[a-z][a-z0-9]{0,3})$#', $path, $matches)) {
    return $next($request, $response);
}

$type = $matches['type'];
if (! in_array($type, array_keys($this->contentTypeMap), true)) {
    return $next($request, $response);
}

if (! file_exists($path)) {
    return $next($request, $response);
}

return $response
    ->withHeader('Content-Type', $this->contentTypeMap[$type])
    ->withBody(new Stream($path, 'r'));
```

The fun part of this is that, because PSR-7 and React both deal with streams,
the approach is incredibly performant, and uses very few resources!

## Making it reusable

To make this reusable, I created a new library,
[phly/react2psr7](https://github.com/phly/react2psr7). This library contains:

- `React2Psr7\ReactRequestHandler`, which accepts a PSR-7 middleware to its
  constructor, and then, for each invocation, marshals a PSR-7 request,
  creates an empty PSR-7 response, dispatches the middleware, and uses the
  returned response to feed the React response.
- `React2Psr7\StaticFiles`, which is the PSR-7 middleware for serving static
  files from the filesystem.

Install it using:

```bash
$ composer require "react/http:^0.5@dev" phly/react2psr7
```

(Since this uses the current development series of react/http, you need to
install that package manually.)

A basic server script for an Expressive application then looks like this:

```php
<?php
// server.php
use React\EventLoop\Factory;
use React\Http\Server as HttpServer;
use React\Socket\Server as Socket;
use React2Psr7\ReactRequestHandler;
use Zend\Expressive\Application;

require_once 'vendor/autoload.php';

$loop      = Factory::create();
$socket    = new Socket($loop);
$http      = new HttpServer($socket);
$container = require 'config/container.php';

$http->on('request', new ReactRequestHandler($container->get(Application::class)));

// Listen on all ports; omit second argument to restrict to localhost.
$socket->listen(1337, '0.0.0.0');
$loop->run();
```

For Expressive, I also added configuration for the `StaticFiles` middleware to
my `config/autoload/middleware-pipeline.global.php` file:

```php
return [
    'dependencies' => [
        'factories' => [
            React2Psr7\StaticFiles::class => React2Psr7\StaticFilesFactory::class,
            /* ... */
        ],
    ],
    'middleware_pipeline' => [
        'static' => [
            'middleware' => React2Psr7\StaticFiles::class,
            'priority' => 100000, // Execute earliest!
        ],
        /* ... */
    ],
];
```

Fire up the server:

```bash
$ php server.php
```

And then start making requests (the following is using [HTTPie](http://httpie.org)):

```bash
$ http GET localhost:1337/api/ping
$ http GET localhost:1337/zf-logo.png
$ http GET localhost:1337/
```

## Next steps

I have a couple things on my roadmap still:

- I need to play with file uploads to see how those are handled, and the impact
  to performance and resource usage. Right now there's a potential for
  duplication of the resources, which makes me hesitant to use it in such
  scenarios.
- I'd like to try and create a variant of the React HTTP server that marshals
  PSR-7 requests and responses and emits the PSR-7 response directly, instead of
  requiring casting. This would largely solve the above problems.
- Documentation for the React project. Currently, each subproject has a README
  file that details the simplest use case, but anything more requires diving
  through the code. In several cases, I determined that methods are often
  overloaded to return promises, but how and where that happens is not clear.
  As such, while the *basics* of the system are fairly easy to pick up, anything
  more requires a ton of domain knowledge, which makes in unapproachable. I'd
  love to help solve that problem through documentation.

In the meantime, I'm quite happy with my weekend experiment!
