Mercure: Real-Time APIs for Serverless and Beyond

Here is the slide deck I presented during API Days SF 2019:

Mercure is a protocol allowing to push data updates to web browsers and other HTTP clients in a convenient, fast, reliable and battery-efficient way. It is especially useful to publish real-time updates of resources served through web APIs, to reactive web and mobile apps. The protocol is designed for serverless, HTTP/2+, hypermedia and GraphQL, and is fully-featured: auto-discoverable, authorization, re-connection, state reconciliation…

Using Next.js and Material UI Together

Next.js is a convenient and powerful framework for React. Its main benefit over using React directly is its transparent support for Server-Side Rendering.
Material UI is a very popular set of React components implementing Google’s Material Design guidelines.

Both libraries are impressive, but there are some tricks to know to make them playing well together.

Bootstrapping

Setting up MUI in a Next project requires some non-trivial tweaks to Next’s initialization process. Conveniently, Material UI provides a skeleton containing a working Next.js project with Material UI already properly configured. It’s the easiest way to kickstart a new project using both tools, don’t miss it!

# Download the skeleton
$ curl https://codeload.github.com/mui-org/material-ui/tar.gz/master | tar -xz --strip=2  material-ui-master/examples/nextjs
$ cd nextjs
# Install the deps
$ yarn install
# Start the project
$ yarn dev

To learn how to integrate Material UI in an existing project, take a look to pages/_document.js and pages/_app.js they contain most the wiring logic.

Forms

Material UI is especially useful because of the large set of form components it provides. But handling forms with React (and so with Next) is tedious and verbose. My colleague Morgan Auchedé recently told me about Formik. Formik is a tiny yet super powerful library allowing to easily create forms with React. And good news: it plays very well with Next! Here is how a basic login form looks when using Formik:

import React from 'react';
import { Formik, Form, Field, ErrorMessage } from 'formik';

export default MyForm = () => (
    <Formik
      initialValues={{ email: '', password: '' }}
      validate={values => {
        // Your client-side validation logic
      }}
      onSubmit={(values, { setSubmitting }) => {
        // Call your API
      }}
    >
      {({ isSubmitting }) => (
        <Form>
          <Field type="email" name="email" />
          <ErrorMessage name="email" />
          <Field type="password" name="password" />
          <ErrorMessage name="password" />
          <button type="submit" disabled={isSubmitting}>
            Submit
          </button>
        </Form>
      )}
    </Formik>
);

Nice! However, when switching to Material UI inputs, the high level helper components provided by Formik become almost useless. Our forms are verbose again. Fortunately, a small library intuitively named formik-material-ui makes it easy to bridge both libraries! Here is the same form as before (including error handling), but rendered using Material UI components:

import React from 'react';
import { Formik, Form, Field } from 'formik';
import { TextField } from 'formik-material-ui';
import Button from "@material-ui/core/Button";

export default MyForm = () => (
    <Formik
      initialValues={{ email: '', password: '' }}
      validate={values => {
        // Your client-side validation logic
      }}
      onSubmit={(values, { setSubmitting }) => {
        // Call your API
      }}
    >
      {({ isSubmitting }) => (
        <Form>
          <Field type="email" name="email" component="TextField" />
          <Field type="password" name="password" component="TextField" />
          <Button
           type="submit"
           fullWidth
           variant="contained"
           color="primary"
           disabled={isSubmitting}
         >
           Submit
         </Button>
        </Form>
      )}
    </Formik>
);

This form is even less verbose, and is now looking good!

Buttons and Routing

Next.js comes with a nice routing system working transparently regardless if the app is executed client-side or server-side. It’s one of the biggest strength of the framework. However, in Material UI, the Button component is often used to trigger navigation between pages, and using buttons with the Router isn’t very intuitive. Still, it’s easy to do:

import React from "react";
import Link from "next/link";
import Button from "@material-ui/core/Button";

export default MyLink = () => (
  <Link href="/pricing" passHref>
    <Button component="a">Managed version</Button>
  </Link>
);

First, we set the component prop of Button to a. It tells Material UI to use an anchor for this button, instead of a… button by default. Then, we set the passHref prop of the Link element, it hints the Router to pass the href prop to the child component, even if doesn’t look like an anchor. Actually (because of the component prop we set earlier), the grandchild will be an anchor, and Material UI will forward the href prop to it! The rendered a element now has a proper href attribute, both client-side and in the server-side generated HTML. Good SEO, for free!

The same trick can be used with the Typography component:

import React from "react";
import Link from "next/link";
import Button from "@material-ui/core/Typography";

export default MyLink = () => (
  <Link href="/pricing" passHref>
    <Typography variant="caption" component="a">Managed version</Typography>
  </Link>
);

This time, we created a link looking like a caption!

That’s all for today. Have fun with Next and Material UI! For more tricks about JavaScript (among various other technologies), follow me on Twitter!

Upcoming conferences: AFUP Day, Web2Day, API Platform Meetup and more!

During the spring I’ll speak at several tech events about my projects Mercure (Go), API Platform (PHP, server-side and JS, client-side) and Symfony Panther (PHP/WebDriver):

AFUP Day, May 17th in Lille

Discover Symfony Panther, a brand new end-to-end testing tool using real web browsers for Symfony and PHP.

API Platform pre-Web2day meetup, June 3th in Nantes

Topic to be announced!

Web2Day, May 6th in Nantes

Mercure: UIs always synchronized with data in database

My company Les-Tilleuls.coop will have a booth during every of these events. Come, and let’s have a chat!
Also, I’ll announce my participation to some more events soon, stay tuned!

React ESI: Blazing Fast SSR

React ESI is a super powerful cache library for vanilla React and Next.js applications, that can make highly dynamic applications as fast as static sites. It provides a straightforward way to boost your application’s performance by storing fragments of server-side rendered pages in edge cache servers. It means that after the first rendering, fragments of your pages will be served in a few milliseconds by servers close to your end users! It’s a very efficient way to improve the performance and the SEO of your websites; and to dramatically reduce both your hosting costs and the energy consumption of these applications. Help the planet, use React ESI!

Because it is built on top of the Edge Side Includes (ESI) W3C specification, React ESI natively supports most of the well-known cloud cache providers including Cloudflare Workers, Akamai and Fastly. Of course, React ESI also supports the open source Varnish cache server that you can use in your own infrastructure for free (configuration example).

Also, React ESI allows to specify a different Time To Live (TTL) per React component and to generate the corresponding HTML asynchronously using a secure (signed) URL. The cache server fetches and stores in the cache all the needed fragments (the HTML corresponding to every React component), builds the final page and sends it to the browser. React ESI also allows components to (re-)render client-side without any specific configuration.

[SymfonyLive Paris slides] Symfony on steroids
: Vue.js, Mercure, Panther

Thanks to the new capabilities of the web platform (web components, Progressive Web Apps…) and the rise of modern JS libraries (Vue, React, Angular) almost all modern Symfony applications must leverage the frontend ecosystem.
Symfony 4 embed many gems that make it easy to integrate modern JavaScript within the framework, including the first component entirely written in JS: Webpack Encore.

In Symfony 4.2, another component that is super convenient for apps containing JS code has been released: Panther, a PHP library compatible with BrowserKit, that drives real web browsers to create end-to-end (E2E) tests with ease.
During this talk, I’ll show you how to cleanly integrate modern JavaScript code with Symfony and Twig and how to test such applications using Panther.

The examples will use VueJS, because it’s probably the easiest JS framework to get started with as a PHP developer, but all the tips and tricks will be applicable with other libraries such as React or Angular.

Finally, we’ll add some real time capabilities to our app using Mercure.rocks

Symfony and API Platform get “push” and real-time capabilities (Mercure protocol)

Mercure.rocks is a brand new protocol allowing to push data updates to web browsers and other HTTP clients in a convenient, fast, reliable and battery-efficient way. It is especially useful to publish real-time updates of resources served through web APIs, to reactive web and mobile apps.

Both Symfony and API Platform now have an official support for this protocol!

From the ground, Mercure has been designed to work with technologies not able to maintain persistent connections. It’s especially relevant in serverless environments, but is also convenient when using PHP or FastCGI scripts.

Mercure is basically a higher-level replacement for WebSocket. Unlike WebSocket, it is compatible with HTTP/2 and HTTP/3.
It has been designed with hypermedia APIs in mind, is auto-discoverable through the Web Linking RFC and is also compatible with GraphQL.
It natively supports authorization, reconnection in case of network issue (with refetching of missed events), subscribing to several topics, topics patterns (using templated URIs)…

Because it is built on top of Server-sent Events and plain old HTTP requests, it is already compatible with all modern browsers, and requires 0 client-side dependencies.

The protocol is open (available as an Internet Draft), and a reference open source implementation of the server written in Go is available.—

API Platform 2.4: MongoDB, Elasticsearch, Mercure, OpenAPI v3, CQRS with Symfony Messenger, HTTP/2 Push, improved React apps and more!

I’m pleased to announce the immediate availability of API Platform 2.4 beta! This new version is a huge one, that comes with a large set of new features.

For newcomers, API Platform is a full-stack framework to develop in a breath high quality API-driven projects. Among other (lower level) libraries, API Platform provides:

API Platform supports modern REST formats (JSON-LD/Hydra, JSONAPI, OpenAPI, HAL…) as well as GraphQL.

To create your initial project, you just have to describe the public structures of the data to expose through the API. API Platform will take care of exposing the web API and bootstrapping the clients to consume it: get started with API Platform.

Version 2.4 introduces a lot of very interesting new features. Here is the curated list:

  • Read and write support for MongoDB, the reference document database, including a lot of useful filters
  • Read support for Elasticsearch, the open source search and analytics engine, including filters for advanced search
  • Automatic “push” of updated resources from the server to the clients using the brand new Mercure protocol
  • Integration with the Symfony Messenger component to easily implement the CQRS pattern and to handle messages asynchronously (using brokers such as RabbitMQ, Apache Kafka, Amazon SQS or Google PubSub)
  • Ability to leverage the “Server Push” feature of HTTP/2 to preemptively send the relations of a requested resource to the client
  • Automatic availability of list filters in the React-based admin when a corresponding one is available API-side
  • Full compatibility with the version 3 of the OpenAPI specification format (formerly known as Swagger), and integration of the beautiful ReDoc documentation generator
  • Improved DTOs support
  • Per resource configuration of HTTP cache headers
  • Ability to easily use the Sunset HTTP header to advertise the removal date of deprecated endpoints

The full changelog is available on GitHub.

Let’s dive into these new features!

MongoDB support

MongoDB is one of the most popular NoSQL database. Native support for MongoDB was the most requested, and the most awaited API Platform feature! Sam Van der Borght started the work in March 2016. In July 2017 the Pull Request has been ported to API Platform v2 by Pablo Godinez helped by Hamza Amrouche (API Platform Core Team), Alexandre Delplace and others. Finally, since August 2018 Alan Poulain (API Platform Core Team and author of the GraphQL subsystem) produced a huge effort to finish and polish the patch.

With 114 commits and 234 files changed over almost 3 years. This is one of the biggest contributions to the project.

The MongoDB integration relies on Doctrine MongoDB ODM 2.0 (currently in beta). To enable this feature, just install and configure DoctrineMongoDBBundle. API Platform will autodetect it. Then, create a class mapped with MongoDB, and mark it as an API resource:

namespace App\Document;

use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;

/**
 * @ApiResource
 * @ODM\Document
 */
class Book
{
    /**
     * @ODM\Id(strategy="INCREMENT", type="integer")
     */
    public $id;

    /**
     * @ODM\Field(type="string")
     */
    public $title;
}

The support for MongoDB leverages the flexibility of API Platform: it has been implemented as a data provider and a data persister. Relations, pagination as well as boolean, date, numeric, order, range and search filters are also supported!

A big thanks to all contributors of this amazing feature, and to Andreas Braun, the maintainer of Doctrine MongoDB ODM, for the in-depth reviews!

Elasticsearch support

Elasticsearch is another very popular open-source data store. It allows to perform full-text searches and advanced analyzes on very large datasets. Orange has sponsored the development of an Elasticsearch data provider for API Platform, as well as some interesting search filters. The implementation has been realized by Baptiste Meyer (API Platform Core Team). Thanks to Orange, this feature is now available for everybody in API Platform 2.4.

To enable and configure the Elasticsearch support, refer to the official documentation. Then, a simple resource class corresponding to an Elasticsearch index is enough to benefit from the full power of API Platform:

namespace App\Model;

use ApiPlatform\Core\Annotation\ApiProperty;
use ApiPlatform\Core\Annotation\ApiFilter;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Bridge\Elasticsearch\DataProvider\Filter\MatchFilter;

/**
 * @ApiResource
 */
class Tweet
{
    /**
     * @ApiProperty(identifier=true)
     *
     * @var string
     */
    public $id;

    /**
     * @var User
     */
    public $author;

    /**
     * @var \DateTimeInterface
     */
    public $date;

    /**
     * @ApiFilter(MatchFilter::class)
     *
     * @var string
     */
    public $message;
}

Then, you can use an URL such as /tweets?message=foo to search using Elasticsearch.

Keep in mind that it’s your responsibility to populate your Elastic index. To do so, you can use Logstash, a custom data persister or any other mechanism that fits for your project (such as an ETL).

Baptiste also took this opportunity to improve the code handling the pagination. It is now a generic class used by all native data providers (Doctrine ORM, MongoDB and Elasticsearch), that you can reuse in your own.

Read and improve the Elasticsearch related documentation.

Real time update of client with Mercure

Mercure is a brand new protocol built on top of HTTP/2 and Server-sent Events (SSE). It’s a modern and high-level alternative to WebSocket (WebSocket is not compatible with HTTP/2). Mercure is especially useful to publish updates of resources served through web APIs in real time. It is natively supported by modern browsers (no required library nor SDK) and is very useful to update reactive web and mobile apps.

In version 2.4, I added Mercure support to the server component of API Platform and to the React and React Native app generators. The Docker Compose setup provided with API Platform has also been updated to provide a Mercure hub.

Configuring the framework to automatically dispatch updates to the currently connected clients is straightforward:

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiResource;

/**
 * @ApiResource(mercure=true)
 */
class Book
{
    // ...
}

Thanks to the auto-discoverability capabilities of Mercure, the generated clients will automatically subscribe to updates, and render them when received:

Mercure in API Platform 2.4

Read and improve the Mercure subsystem documentation.

CQRS and async message handling with Symfony Messenger

Messenger is a new Symfony component created by Samuel Roze (Symfony and API Platform Core Team). It allows to dispatch messages using message queues (RabbitMQ, Kafka, Amazon SQS, Google PubSub…) and to handle them asynchronously. It provides a message bus that is very useful to implement the CQRS design pattern.

In API Platform 2.4, I added a convenient way to leverage the capabilities of Messenger. This new feature is particularly useful to create service-oriented (RPC-like) endpoints:

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ApiResource(
 *     messenger=true,
 *     collectionOperations={
 *         "post"={"status"=202}
 *     },
 *     itemOperations={},
 *     output=false
 * )
 */
class ResetPasswordRequest
{
    /**
     * @var string
     *
     * @Assert\NotBlank
     */
    public $username;
}

Thanks to the new messenger attribute, this object will automatically be dispatched to the bus. It can then be handled (synchronously or asynchronously) by a message handler:

namespace App\Handler;

use App\Entity\ResetPasswordRequest;
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;

class ResetPasswordRequestHandler implements MessageHandlerInterface
{
    public function __invoke(ResetPasswordRequest $forgotPassword)
    {
        // do something with the resource
    }
}

That’s all you need to use Messenger!

Read and improve the Messenger subsystem documentation.

Server Push

HTTP/2 allows a server to pre-emptively send (or “push”) responses (along with corresponding “promised” requests) to a client in association with a previous client-initiated request. This can be useful when the server knows the client will need to have those responses available in order to fully process the response to the original request.

RFC 7540


This is capability is especially useful for REST APIs performance: it allows the server to instantly push the relations of the current resource that will be needed by the client, even before the client knows that it will have to issue an extra HTTP request.

API Platform 2.4 makes it very easy to push relations using HTTP/2:

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiProperty;
use ApiPlatform\Core\Annotation\ApiResource;

/**
 * @ApiResource
 */
class Book
{
    /**
     * @ApiProperty(push=true)
     *
     * @var Author
     */
    public $author;
}

Thanks to the push attribute, if the client asks for /books/1 the web server will directly send both the requested book resource and the related author (e.g. /authors/12) to the client.

For best performance, this feature should be used in conjunction with the built-in HTTP cache invalidation system (based on Varnish).

Read and improve the HTTP/2 Server Push subsystem documentation.

Filters detection in API Platform Admin

Jean-François Thuillier and Arnaud Oisel patched API Platform Admin and the underlying API Doc Parser JavaScript library to automatically detect and use filters exposed by the API spec (Hydra or OpenAPI). A video is worth thousand words:

Filters support in API Platform

The only code that you need to get such UI is the following:

import React from 'react';
import { HydraAdmin } from '@api-platform/admin';

export default () => <HydraAdmin entrypoint="https://api.example.com"/>;

The UI is built client-side dynamically by parsing the API spec. Awesome isn’t it?

Jean-François also added some convenient helpers to help customizing the admin, and Laury Sorriaux fixed a long standing limitation: it’s now possible to use the admin even with API not served at the root of the domain (such as /api).

Read and improve the docs of API Platform Admin.

OpenAPI v3 and ReDoc

API Platform 2.4 now fully support the new version of the OpenAPI (formerly Swagger) specification format (v3). It also leverages new features introduced by this version such as links.

To retrieve the OpenAPI specification of the API in version, use the following url: /docs.json?spec_version=3.

You can also dump the specification in JSON or in YAML format:

  • bin/console api:openapi:export --spec-version=3 # JSON
  • bin/console api:openapi:export --spec-version=3 --yaml # YAML

Also, in addition to Swagger UI, we added support for ReDoc, a beautiful, human-readable, API docs generator written in React:

ReDoc in API Platform 2.4

OpenAPI v3 support has been contributed by Anthony Grassiot (API Platform Core Team). ReDoc integration has been contributed by Grégoire Hébert. A big thanks to them!

Read and improve the OpenAPI related documentation.

Improved DTO support

Handling Data Transfer Objects was known to be difficult with API Platform. Back in October, the API Platform and the Sylius teams worked together to improve the API of the popular e-commerce solution… using API Platform (stay tuned!). During this workshop Antoine Bluchet and I worked on a new way to handle DTOs with API Platform:

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use App\Dto\BookInput;
use App\Dto\BookOutput;

/**
 * @ApiResource(
 *   input=BookInput::class,
 *   output=BookOutput::class
 * )
 */
final class Book
{
  // ...
}

The new input and output attributes allow to use specific classes respectively for the writeable and the readable representation of the resource.

As demonstrated in the example using Symfony Messenger, it’s also possible to set these new attributes to false to hint that the operation will take no inputs or no outputs.

These new attributes are automatically taken into account by all API Platform subsystems, including GraphQL, Hydra and OpenAPI.

Read and improve the DTO related documentation.

Cache HTTP headers

A convenient way has been to configure the HTTP cache per resource has been added by Daniel West:

use ApiPlatform\Core\Annotation\ApiResource;

/**
 * @ApiResource(cacheHeaders={"max_age"=60, "shared_max_age"=120})
 */
class Book
{
    // ...
}

With this config, API Platform will automatically generate the following Cache-Control HTTP header: Cache-Control: max-age=60, public, s-maxage=120. Thanks Daniel!

Read and improve the HTTP cache headers documentation.

Sunset HTTP header

The Sunset HTTP response header field indicates that a URI is likely to become unresponsive at a specified point in the future.

draft-wilde-sunset-header Internet Draft

This header plays well with the deprecation mechanism available since API Platform 2.3. Thanks to a nice contribution of Thomas Blank, it’s now easy to set this header using API Platform:

namespace App\Entity;

/**
 * @ApiResource(itemOperations={
 *     "get"={
 *         "deprecation_reason"="Retrieve a Book instead",
 *         "sunset"="01/01/2020"
 *     }
 * })
 */
class Parchment
{
    // ...
}

Read and improve the documentation related to API evolution.

Improved client generator

API Platform 2.4 is shipped with an improved version of the React and Vue.js client generators:

  • Relations are now always handled properly
  • HTML number fields as well as lists (arrays) are converted to the appropriate JSON type when sent to the API
  • API not server at the root of the domain (such /api) are now supported (thanks to Fabien Kovacic)

Download and promote API Platform

API Platform 2.4 is available for download on GitHub. While you are here, if you like the project, help us making it popular by starring it on GitHub!

[SymfonyCon slides] Progressively enhance your Symfony 4 app using Vue, API Platform, Mercure and Panther

Thanks to the new capabilities of the web platform (web components, Progressive Web Apps…) and the rise of modern JS libraries (Vue, React, Angular) almost all modern Symfony applications must leverage the frontend ecosystem.
Symfony 4 embed many gems that make it easy to integrate modern JavaScript within the framework, including the first component entirely written in JS: Webpack Encore.

In Symfony 4.2, another component that is super convenient for apps containing JS code has been released: Panther, a PHP library compatible with BrowserKit, that drives real web browsers to create end-to-end (E2E) tests with ease.
During this talk, I’ll show you how to cleanly integrate modern JavaScript code with Symfony and Twig and how to test such applications using Panther.

The examples will use VueJS, because it’s probably the easiest JS framework to get started with as a PHP developer, but all the tips and tricks will be applicable with other libraries such as React or Angular.

Finally, we’ll add some real time capabilities to our app using Mercure.rocks

NPM dependency hell: comparison with Symfony, Laravel and API Platform

You may have noticed the recent fuss about the compromise of event-stream, a popular NPM package:

event-stream is a transitive dependency of many popular JavaScript projects including Vue, Angular, Gatsby and VSCode (some of them are using a version that isn’t affected by the attack).

This attack raised, again, the problem of the JS dependency cascade: when you install a major project, it comes with hundreds of tiny libraries, sometimes not maintained, and sometimes coming from untrusted sources.

Some claimed that the problem wasn’t specific to the JavaScript ecosystem, and that projects in other languages such as Rails and Symfony were also suffering from a similar dependency hell.
A Twitter poll created by Rafael Dohms highlights that most developers believe that it’s only a matter of luck if this issue has affected the JavaScript ecosystem, and not the PHP one:

Regarding Symfony, as a maintainer I have the feeling that the Symfony Core Team (carefully) adds dependencies only when strictly necessary. However I had no metrics to prove it. So I checked. Then I compared with other PHP frameworks I’m interested in: Laravel and API Platform.

Symfony

When installing Symfony 4.1 using the official skeleton, only 20 packages are downloaded (19 when excluding dev dependencies). 16 are directly maintained by the Symfony project, and the 4 others are interfaces from the PHP Framework Interoperability Group:

$ composer create-project symfony/skeleton nb-deps

$ composer info | wc -l

20

$ composer info | cut -d/ -f1 | uniq

psr

symfony

Even when installing the website skeleton, that comes with all features provided by the framework and third party (trusted) packages such as the Doctrine ORM, the Twig templating library or Swift Mailer, only 94 packages (75 when excluding dev dependencies), from 17 different organisations (14 without dev deps) are installed:

$ composer create-project symfony/website-skeleton nb-deps

$ composer info | wc -l

94

$ composer info | cut -d/ -f1 | uniq

doctrine

easycorp

egulias

facebook

fig
jdorn

monolog

nikic

ocramius

phpdocumentor

psr

sensio
swiftmailer

symfony

twig

webmozart

zendframework

Among these vendors, 7 are directly maintained by members (or former members) of the Symfony Core Team (easycorp, monolog, sensio, swiftmailer, symfony, twig, webmozart) and 2 are from the FIG. All these few libraries, except maybe jdorn/sql-formatter, are actively maintained, by prominent and well known members of the PHP community.

API Platform

A minimal installation of the server part (the one written in PHP) of the API Platform framework contains only 27 packages (26 without dev deps) from 5 vendors.

$ composer create-project symfony/skeleton nb-deps

$ composer require api-platform/core

$ composer info | wc -l

27

$ composer info | cut -d/ -f1 | uniq

api-platform

doctrine

psr

symfony

willdurand

When installing the API pack, that provides all features you can expect from an advanced web API (hypermedia support, automatic persistence with the Doctrine ORM support, automatic generation of human-readable documentation, CORS support, authorisation rules…), 57 packages (56 without dev deps) from 10 vendors are shipped.

$ composer create-project symfony/skeleton nb-deps

$ composer require api

$ composer info | wc -l

57

$ composer info | cut -d/ -f1 | uniq
api-platform

doctrine

jdorn

nelmio

phpdocumentor

psr

symfony

twig

webmozart

willdurand

On the other hand, the API Platform distribution comes with (optional) frontend tools: an admin and a Progressive Web Apps and mobile apps generator. They are built-on top of React, so even if the JavaScript libraries directly maintained by the API Platform team depend of just a few carefully selected libraries… these dependencies are typical JavaScript ones, and come with hundreds of dependencies (see after).

Laravel

The default installation of Laravel (that is somewhat similar in term of features to the Symfony website skeleton) comes with 72 packages (39 when excluding dev deps) from 35 vendors (21 when excluding dev deps).

$ laravel new nb-deps

$ composer info | wc -l
72

$ composer info | cut -d/ -f1 | uniq
dnoegel
doctrine
dragonmantank
egulias
erusev
fideloper
jakub-onderka
laravel
league
monolog
nesbot
nikic
opis
paragonie
psr
psy
ramsey
swiftmailer
symfony
tijsverkoyen
vlucas

The number of maintainers you have to trust when using Laravel is just a bit larger than when using Symfony, but again it’s still a bunch of people that are well known in the PHP community, and who may fit in a single room.

In comparison, a default installation of React using Create React App – that is more similar to the minimal Symfony skeleton than to fully-featured frameworks such as the Symfony website skeleton or Laravel – comes with 809 packages, most of them being maintained by different teams or individuals.

Another main difference is that most JS libraries are distributed as compiled and minified builds. Therefore it’s very difficult to guarantee that what is shipped and executed behaves exactly the same way than the code in the sources. In PHP, the source of the libraries are used directly, without intermediate obfuscation.  PHP builds are easy to reproduce, it helps a lot when auditing.

Of course, it doesn’t mean that major PHP frameworks are immune to this kind of attacks and – as any IT project – they also have their own security issues. However, the amount of third party code installed and the chain of trust you have to rely on is more under control than in the JS world.

By the way, you’d better actively monitor the security vulnerabilities that may affect your PHP projects.

HTTP/2: speed up your apps and dispatch real time updates (Symfony and API Platform’s features announcement)

HTTP/2 can improve the loading time of webpages up to 2 times. Did you know that it’s very easy to optimize your Symfony applications to leverage the advanced features of this new protocol?

This talk also contains the announcement of 3 new PHP packages:

Agenda:

  • a historically contextualized presentation of the different versions of the HTTP protocol;
  • a state of the protocol support in the PHP ecosystem;
  • a guide explaining how to serve your PHP and Symfony apps with h2, using Nginx, Apache and Docker;
  • many code samples showing how to use h2 to improve the loading time of your assets and APIs using the WebLink component and Twig
  • examples of how to take advantage of the protocol using the curl and Guzzle clients
  • the Mercure Protocol
  • Mercure x Symfony
  • Mercure x API Platform