Developing web APIs
using middleware in PHP 7

by Enrico Zimuel
Senior Software Engineer
Zend, a Rogue Wave Company (USA)

ApiConf, Turin, 15th June 2017

About me


  • PHP: Hypertext Preprocessor
  • The most popular server-side language: PHP is used by 82.6% of all the websites (source:
  • Used by Facebook, Wikipedia, Yahoo, Etsy, Flickr, Digg, etc
  • 22 years of usage, since 1995
  • Full OOP support since PHP 5


Released: 3 December 2015

Previous major was PHP 5, 13 July 2004

Skipped PHP 6: Unicode failure

Last release is 7.1.6 (8 Jun 2017)

PHP 7 performance

PHP 7 is also faster than Python 3!


$a = [];
for ($i = 0; $i < 1000000; $i++) {
  $a[$i] = ["hello"];
echo memory_get_usage(true);
PHP 5.6 PHP 7
Memory Usage 428 MB 33 MB
Execution time 0.49 sec 0.06 sec

Moving to PHP 7

  • Badoo saved one million dollars switching to PHP 7 (source)
  • Tumblr reduced the latency and CPU load by half moving to PHP 7 (source)
  • Dailymotion handles twice more traffic with same infrastructure switching to PHP 7 (source)

PHP 7 is not only fast!

  • Return and Scalar Type Declarations
  • Improved Exception hierarchy
  • Many fatal errors converted to Exceptions
  • Secure random number generator
  • Authenticated encryption AEAD (PHP 7.1+)
  • Nullable types (PHP 7.1+)
  • and more!

Web APIs in PHP 7




GET /api/version


HTTP/1.1 200 OK
Connection: close
Content-Length: 17
Content-Type: application/json

  "version": "1.0"


A function that gets a request and generates a response

use Psr\Http\Message\ServerRequestInterface as Request;
use Interop\Http\ServerMiddleware\DelegateInterface;

function (Request $request, DelegateInterface $next)
    // doing something with $request...
    // for instance calling the delegate middleware $next
    $response = $next->process($request);
    // manipulate the $response
    return $response;
This is called lambda middleware.


namespace Interop\Http\ServerMiddleware;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

interface DelegateInterface
     * @return ResponseInterface;
    public function process(ServerRequestInterface $request);
DelegateInterface is part of PSR-15 HTTP Middleware proposal

Expressive 2.0

The PHP framework for Middleware applications

  • PSR-7 HTTP Message support (using zend-diactoros)
  • Support of lambda middleware (PSR-15) and double pass ($request, $response, $next)
  • Piping workflow (using zend-stratigility)
  • Features: routing, dependency injection, templating, error handling
  • Last release 2.0.3, 28th March 2017


You can install Expressive 2.0 using composer:

composer create-project zendframework/zend-expressive-skeleton api

Choose the default options during the installation


The skeleton has 2 URL as example: / and /api/ping

The routes are registered in /config/routes.php

The middleware actions are stored in /src/App/Action


$app->get('/', App\Action\HomePageAction::class, 'home');
$app->get('/api/ping', App\Action\PingAction::class, '');

API Middleware

namespace App\Action;

use Interop\Http\ServerMiddleware\DelegateInterface;
use Interop\Http\ServerMiddleware\MiddlewareInterface;
use Zend\Diactoros\Response\JsonResponse;
use Psr\Http\Message\ServerRequestInterface;

class PingAction implements MiddlewareInterface
    public function process(
        ServerRequestInterface $request,
        DelegateInterface $delegate
    ) {
        return new JsonResponse(['ack' => time()]);

Pipeline workflow





Service Container

use Zend\ServiceManager\Config;
use Zend\ServiceManager\ServiceManager;

$config = require __DIR__ . '/config.php';
$container = new ServiceManager();
$config = new Config($config['dependencies']);
$container->setService('config', $config);

return $container;

The Expressive app

require 'vendor/autoload.php';

call_user_func(function () {
    $container = require 'config/container.php';
    $app = $container->get(\Zend\Expressive\Application::class);

    require 'config/pipeline.php';
    require 'config/routes.php';


Route a REST API

$app->route('/api/users[/{user-id}]', [
], ['GET', 'POST', 'PATCH', 'DELETE'], 'api.users');

// or route each HTTP method
$app->get('/api/users[/{user-id}]', ..., 'api.users.get');
$app->post('/api/users', ..., '');
$app->patch('/api/users/{user-id}', ..., 'api.users.patch');
$app->delete('/api/users/{user-id}', ..., 'api.users.delete');

Rest Dispatch Trait

use Psr\Http\Message\ServerRequestInterface;
use Interop\Http\ServerMiddleware\DelegateInterface;

trait RestDispatchTrait
    public function process(
        ServerRequestInterface $request,
        DelegateInterface $delegate
    ) {
        $method = strtolower($request->getMethod());
        if (method_exists($this, $method)) {
            return $this->$method($request);
        return $response->withStatus(501); // Method not implemented

REST Middleware

class UserAction implements MiddlewareInterface
    use RestDispatchTrait;

    public function get(ServerRequestInterface $request)
        $id = $request->getAttribute('user-id', false);
        $data = (false === $id) ? /* all users */ : /* user id */;
        return new JsonResponse($data);

    public function post(ServerRequestInterface $request){ ... }
    public function patch(ServerRequestInterface $request){ ... }
    public function delete(ServerRequestInterface $request){ ... }


More info:

Contact me: enrico.zimuel [at]

Follow me: @ezimuel

Creative Commons License
This work is licensed under a
Creative Commons Attribution-ShareAlike 3.0 Unported License.
I used reveal.js to make this presentation.