Speed up web APIs in PHP
with Expressive

by Enrico Zimuel
Senior Software Engineer
Rogue Wave Software (USA)


APIConf 2018, Turin (Italy), 21th Jun

About me

PHP 7 book


Sviluppare in PHP 7 *

pp. 352, Tecniche Nuove, 2017
ISBN 978-88-481-3120-9

* in Italian

Web API

Building a Web API

  • Managing the HTTP request and response
  • Choosing a representation format
  • Choosing an error format
  • Filtering & validating input data
  • Authenticating HTTP requests
  • Authorizing HTTP requests
  • Documentation

HTTP request in PHP

Global variables (bad!):

  • $_SERVER
  • $_POST
  • $_GET
  • $_FILES
  • $_COOKIE

HTTP response in PHP

  • http_response_code()
  • header(), header_remove(), headers_list(), headers_sent()
  • setcookie(), setrawcookie()
  • etc

Please OOP!

PSR-7

  • PHP Standards Recommendations (PSR)
  • Part of PHP Framework Interop Group (PHP FIG)
  • PSR-7 is a collection of interfaces for representing HTTP messages as described in RFC 7230 and RFC 7231, and URIs for use with HTTP messages as described in RFC 3986

Example


// Request
$header = $request->getHeader('Accept');
$query  = $request->getQueryParams();
$body   = $request->getBodyParams();

// Response
$response = $response->withStatus(418, "I'm a teapot");
$response = $response->withBodyParams(json_encode($body));

Middleware

Middleware

A function that gets a request and generates a response


function ($request)
{
    // do something with $request
    return $response;
}

Delegating middleware

Create a pipeline of execution


function ($request, $delegate)
{
    // delegating another middleware
    $response = $delegate($request);
    return $response;
}

Example: cache


function ($request, $delegate) use ($cache)
{
    if ($cache->has($request)) {
        return $cache->get($request);
    }
    $response = $delegate($request);
    $cache->set($request, $response);
    return $response;
}

Expressive

The PHP framework for middleware applications

  • PSR-7 support (using zend-diactoros)
  • PSR-15 support
  • Piping workflow (using zend-stratigility)
  • Features: routing, dependency injection, templating, error handling
  • Last release 3.0.6, 16th April 2018

A basic web API


use Zend\Diactoros\Response\JsonResponse;
use Zend\Expressive\Application;

$container = require 'config/container.php';

$app = $container->get(Application::class);

$app->pipe('/api/ping', function($request) {
    return new JsonResponse(['ack' => time()]);
});
// or $app->pipe('/api/ping', \App\Handler\PingHandler::class);
$app->run();

Request Handler


use Psr\Http\Message\ResponseInterface; // PSR-7
use Psr\Http\Message\ServerRequestInterface; // PSR-7
use Psr\Http\Server\RequestHandlerInterface; // PSR-15
use Zend\Diactoros\Response\JsonResponse;

class PingHandler implements RequestHandlerInterface
{
    public function handle(
        ServerRequestInterface $request
    ) : ResponseInterface
    {
        return new JsonResponse(['ack' => time()]);
    }
}

Example: Routing REST API


$app->route('/api/users[/{id}]', [
    Authentication\AuthenticationMiddleware::class,
    Authorization\AuthorizationMiddleware::class,
    Api\Action\UserAction::class
], ['GET', 'POST', 'PATCH', 'DELETE'], 'api.users');

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

Quick start

You can start using Expressive with composer:

composer create-project zendframework/zend-expressive-skeleton <dir>

Expressive tool for API

REST example

github.com/ezimuel/zend-expressive-api

Swoole

  • Swoole is an async programming framework for PHP 7
  • PHP extension, install:
    
    pecl install swoole
    
  • Released under Apache license 2.0
  • More info at swoole.co.uk

Features

  • Event-driven, asynchronous programming for PHP
  • Async TCP / UDP / HTTP / Websocket / HTTP2 client/server side API
  • IPv4 / IPv6 / Unixsocket / TCP/ UDP and SSL / TLS support
  • High performance, scalable, support C1000K
  • Fast serializer / unserializer
  • Milliseconds task scheduler

HTTP Server


$http = new swoole_http_server("127.0.0.1", 9501);

$http->on("start", function ($server) {
    echo "Started at http://127.0.0.1:9501\n";
});

$http->on("request", function ($request, $response) {
    $response->header("Content-Type", "text/plain");
    $response->end("Hello World\n");
});

$http->start();

Expressive with Swoole

Use zendframework/zend-expressive-swoole library
(dev version):


composer require zendframework/zend-expressive-swoole:dev-master

Usage:


php public/index.php

Runs at localhost:8080 by default

Swoole is 4x faster

Thanks!

Contact: enrico.zimuel [at] roguewave.com

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.