API Platform 2.6

API Platform 2.6: PHP 8 support, Next.js and Nuxt.js app generator, Caddy server, ActivityPub and much more!

During my talk at SymfonyWorld, I announced the immediate availability of API Platform 2.6 (alpha version)! Try it now!

Version 2.6 is the result of more than one year of work and hundreds of commits. It contains a huge list of new features, checkout the change logs (core library, distribution) for the full list. In this blog post, I’ll present the major new features! You can also take a look at the slide deck I presented (go on SpeakerDeck for the transcript):

See also the French translation of this article.

PHP 8 Support

PHP 8 was released one week ago, and it comes with a huge list of new features. Among these features, attributes are a game changer for API Platform, as it relied a lot on annotations.

Starting with API Platform 2.6 you can use every annotation classes as PHP 8 attributes:

<?php

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiResource;

#[ApiResource]
class Book
{
    public function __construct(
        public string $id,
        public string $title
    ) {}
}

API Platform is now also fully compatible with PHP 8 (all deprecations have been fixed), and PHP 8 is now the default in the API Platform Distribution!

Next.js and Nuxt.js Support

API Platform comes with a very practical tool to scaffold client applications: the client generator. This generator uses the Hydra or OpenAPI (experimental) documentation of the API to generate apps using various client-side technologies. It works with any API documented using these formats, not only with APIs using the server-side component of API Platform!

Generating TypeScript interfaces as well as of Progressive Web Apps built with React Native, React/Redux, Vue.js, Quasar and Vuetify was already supported. In API Platform 2.6, this tool gained support for Next.js!

Next.js is the reference framework in the React ecosystem. It is very easy to use, supports Server-Side Rendering out of the box, has a simple yet powerful page-based routing system and supports a wide range of features.

We also updated the API Platform distribution to use Next.js by default. A Docker container and a Docker Compose definition will start a skeleton of a Next.js app automatically and you will be able to scaffold your pages and forms by running a single command!

API Platform Admin is now also integrated in this Next.js app, on the /admin route.

You prefer using Vue instead of React? We’ve got you covered! In API Platform 2.6 we also introduced a Nuxt.js generator. Nuxt.js is similar to Next.js, but using Vue! And, as API Platform, it has been created by French folks!

Simplifying the API Platform Distribution with Caddy Server

In API Platform 2.6, the distribution has been totally revamped. API Platform supports many advanced features out of the box, including the Mercure and Vulcain protocols. To support these features, API Platform came with many Docker containers:

  • PHP FPM
  • NGINX
  • A container to generate TLS certificates
  • Vulcain reverse proxy
  • Mercure Hub
  • Postgres
  • A Node.js container for the client generator
  • A Node.js container for the admin app

In API Platform 2.6, we simplified everything! First, we switched from NGINX to the awesome Caddy web server. Caddy is fast, fully-featured and extensible. For instance, it generates TLS certificates automatically both in production and on local development environment and natively supports PHP FPM. We also created Caddy modules for Mercure and for Vulcain! We’re also working with the Caddy team to create an HTTP cache module that will replace Varnish.

As explained in the previous section, we also replaced Create React App by Next.js and merged the containers for the client and the admin.

The result is a very simplified setup:

  • PHP FPM
  • Caddy web server
  • Postgres (optional)
  • Next.js container (optional)

We also added support for a production mode to the Docker Compose definition included in the distribution.

Better Configuration

Until now, it wasn’t possible to define global configuration defaults applied to all resources and all operations. You had to copy your configuration in all resource definitions. Starting with API Platform 2.6, you can define a global default configuration:

# config/packages/api_platform.yaml
api_platform:
    defaults:
        itemOperations: ["get"]
        collectionOperations: ["get"]
        mercure: true

With the previous config, write routes are disabled for the whole API, and Mercure support (async API) is enabled for all resources!

Access Control for Properties

API Platform supports resource-based access control. In 2.6, we introduced support for property-based access control:

<?php

namespace App\Entity;

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

#[ApiResource]
class Book
{
    #[\ApiProperty(security: "is_granted('ROLE_ADMIN')"]
    public $adminOnlyProperty; 
}

Thanks to this rule, the adminOnlyProperty will be serialized only for users having the admin role! Other users will not be able to see it.

ActivityPub Component

As you may know, I’m very worried by the current state of the web, and I think that we must fight to decentralize the web again.

ActivityPub is a specification edited by the W3C unlocking interoperability between social networking applications. It’s part of the solution to fight global censorship and to move out of the walled gardens of big tech companies. ActivityPub is already implemented by many software including Mastodon (Twitter-like), PeerTube (YouTube-like), PixelFed (Instagram-like), Mobilizon (Meetup-like)… This ecosystem is called the Fediverse.

In API Platform 2.6, we introduced a new experimental component allowing to add support for ActivityPub in any API Platform or Symfony application! It’s now way easier than before to build federated apps and to grow the Fediverse!

Community

The biggest strength of API Platform is its community of users and contributors! To celebrate our vibrant community, we added new pages to the website dedicated to the community. Each contributor now has a dedicated page including a summary of their contributions. Discover our awesome community!

And to thank contributors, we’re also offering nice t-shirts to them as part of the Hacktoberfest initiative!

API Platform 3

The next version of API Platform will be API Platform 3! We’ll release API Platform 2.7 at the same time. API Platform 3 will basically be API Platform 2.7 minus the backward compatibility layer with the deprecated code.

API Platform 3 will promote subresources as first-class citizens! They will support write operations. The overall configuration is also being revamped.

Also, to reduce the maintenance burden, API Platform 3 will only support PHP 8 and Symfony 5.2+! Be prepared.

Misc

They are also loads of new features in API Platform 2.6 not listed in this blog post: our GraphQL subsystem gained a lot of new features (including support for subscriptions and page-based pagination), the MongoDB bridge now supports the Mercure protocol, the OpenAPI builder has been totally rewritten, composed identifiers are easier to handle… Read the change logs (core library, distribution) to discover all of them!

I want to thank all contributors having contributed code and documentation for API Platform 2.6! Nothing would be possible without you.

Please try the alpha version and report any bugs!

If you have not yet given a GitHub star to the project, please do, it helps a lot to promote it.

If you like my work on the project, please also consider sponsoring me!

Save the Web: Decentralize!

The web was designed to serve humanity, to enable knowledge sharing, for friendship among people.
But data and services centralization by the Tech Giants have completely perverted it. Centralization causes major threats to our societies: mass surveillance, censorship, vote rigging, opponents arrests , advertising tracking.

The situation is such that the founding fathers of the web, including its creator Tim Berners-Lee, multiply the calls to save it.

The solution: decentralize it again, give users control over their data, fight against GAFAM monopolies, rebuild an independent and non-commercial web based on free software.

Developers, journalists, lawyers, artists and activists are organizing to bring out the “Dweb”, the decentralized and distributed web (again). The Dweb is a corpus of standards (usually published by the W3C) such as ActivityPub, JSON-LD, RDF or HTTP as well as tools including Solid, Mastodon, PeerTube or Mobilizon which aim to put the Web at the service of common good.

As web developers, it is our responsibility to build and promote this new web.

The good news is that the PHP ecosystem now has the tools to easily create decentralized web applications based on these standards. During this conference, we will discover why the Dweb is a crucial issue for the future of our societies, how it works technically, and how we implement it with API Platform!

To do so, I just published a new API Platform component: API Platform ActivityPub! This new libraries component allows:

  • Build apps supporting ActivityPub in minutes!
  • Add ActivityPub support to any existingAPI Platform or Symfony app
  • 100% customizable
  • Compatible with all API Platform features
  • State of the art PHP / API Platform

Check it out!

Say Hello to Mercure 0.10!

I’m very excited to announce the immediate availability of the version 6 of the Mercure Internet Draft as well as of the version 0.10 of the reference implementation!

Mercure is a real-time protocol built on top of Server-sent Events and leveraging HTTP/2+. It allows to push messages to JavaScript webapps, mobile apps or IoT devices with ease. Client-side, it relies on the native EventSource class and doesn’t require any JS dependency. Server-side, it allows to use a Hub to handle persistent connections and dispatch messages sent, for instance, from your REST or GraphQL APIs. An open source Hub designed for performance and high loads is developed in parallel to the specification. Get started with Mercure.

Since the initial release of Mercure, we gather feedback from the ever-growing community of users and contributors. This allowed us to identify the pain points, some limitations and new use cases. It took months of work to get there, but these new versions of the protocol and of the FOSS hub (written in Go) fix all the limitations and design issues we identified so far. They are by far the best and the fastest versions ever released! Let’s discover these changes and new features.

Protocol Changes

Authorization Mechanism

One of the key features of Mercure is its authorization mechanism. It allows to send private updates, which will be received only by subscribers having the appropriate credentials.

Until the last version of the protocol, this mechanism was using the concept of targets, and was hard to understand for newcomers.
In the 6th version of the protocol, the authorization mechanism has been dramatically simplified, while staying as powerful as before.

The authorization mechanism has been totally revamped and the concept of targets is gone. Now, to send a private update, the publisher must only mark it as private when sending the POST request to the hub using the new private parameter.

On the other hand, to receive a private update, a subscriber must present a JWT to the hub containing a list of topic selectors in the mercure.subscribe claim of the token.

A private update will be received by a subscriber only if:

  • the topic of the update is contained in the list of topic selectors
  • the topic matches an URI template present in the list
  • the topic selectors list contains the special value *, which allows to receive all updates.

More advanced use cases such as cherry-picking which updates will be received by a subscriber are also supported thanks to existing features such as alternate topics.

Also, the new concept of target selectors can also be used to subscribe to (public or private) updates, making the whole protocol more consistent.

Learn more about topic selectors and the authorization mechanism.

Presence API

One of the most requested feature was the ability to retrieve the list of currently connected subscribers. This is now possible thanks to a new web API exposed by the hub! It’s also possible for a subscriber to receive Mercure updates when other subscribers connect or disconnect.

Hubs can now expose endpoints returning the list of connected users as JSON-LD documents:

  • /.well-known/subscriptions returns the list of all active subscriptions
  • /.well-known/subscriptions/{topic} returns the list of active subscriptions for a specific topic
  • /.well-known/subscriptions/{topic}/{subscriber} returns details for a single subscription

Also, after having fetched the initial list of connected users, clients can subscribe (using the standard subscription mechanism) to connection status updates by using these URIs as topics.

To access to this presence API, subscribers must be authenticated and have topic selectors matched by these URIs.

Finally, arbitrary data (such as the subscriber’s username or IP address) can be attached to a subscription and retrieved by other subscribers using the new mercure.payload JWT claim.

The debug UI shipped with the reference hub now supports this new feature:

Learn more about active Mercure subscriptions.

Event Sourcing

The native features of Mercure, including its built-in history and its state reconciliation mechanism make it a convenient solution to implement Event Sourcing.

The latest version of the protocol introduces changes making dedicated to this kind of usages.

First, it is now possible to set the value of the Last-Event-ID HTTP header (or of the query parameter with the same name) to earliest to retrieve the all past events. This allows to use the Mercure hub similarly to Apache Kafka, but directly from the browser (or any other kind of HTTP client).

Additionally, when a Last-Event-ID header or parameter is set, the hub will now always return a Last-Event-ID header in the HTTP response. If it matches the requested one, it means that all requested events have been returned, otherwise, it means that the requested event may have been deleted by the hub (if it stores a limited number of events for instance), or that this event ID doesn’t exist.

Learn more about Event Sourcing and state reconciliation capabilities of Mercure.

IRIs, Strings, and Fragment Identifiers

The protocol has been made more consistent by allowing to use IRIs (recommended) or plain strings (discouraged but sometimes practical) for every identifiers: topics, event IDs, subscriber IDs…

Event IDs starting by the # character (URI fragment) are now reserved for generation by the hub. This allows a hub to use offsets generated by systems such as Apache Kafka, Apache Pulsar or Redis Streams as update identifiers while keeping these identifiers globally unique (because they are relative to the Hub URI).

Changes in the Reference Implementation

All the features described previously have already been implemented in the reference implementation (the open source hub written in Go). But that’s not all! The hub has also been dramatically improved during the past few months.

New Engine

Until version 0.10, the reference hub was using an engine working like this: when a new update was posted by a publisher, a new light-weight process (goroutine) was started and the update was pushed to every active subscriber in a loop. If a Last-Event-ID header (or parameter) was passed by a subscriber to request past events, these past events were retrieved from the persistence layer and dispatched from another goroutine.

However, this approach had several drawbacks:

  • If a subscriber was slow to receive an update, it was slowing down the main loop, and so increasing the latency also for other subscribers.
  • If a Last-Event-ID was passed, new events could be received before events coming from the history (for example, when a new event was sent from the main goroutine while another goroutine was still retrieving past events from the persistence layer). The order in which events were received wasn’t 100% guaranteed.

Mercure 0.10 contains a brand new engine that fixes these issues! This new engine leverages thoroughly the iconic features of the Go programming language: channels and goroutines. Now, two buffers are assigned to each subscribers: the first one stores events coming from the history while the second one stores “live” events. When a new event is published, the main goroutine pushes this event in the “live” buffers without waiting for events to be dispatched. Then a dedicated goroutine per subscriber pops events from the buffers associated with it. So every subscriber can receive the events as its own pace, without impacting the rest of the system.

This buffer system also fixes the order issue: goroutines dedicated to specific subscribers wait for all updates coming from the history to be dispatched before starting to dispatch updates stored in the “live” buffer.

Last but not least, this new system allows to disconnect subscribers that are too slow to receive the updates. A new config option, dispatch_timeout, has been introduced to configure the maximum time that a subscriber can take to receive an update before being disconnected to free resources.

If you’re interested in the internals, take a look at this piece of Go code!

A big thanks to Dani Kaplan for his precious help testing and debugging this new engine under high loads!

Prometheus and Health Checks Support

Prometheus is a very popular monitoring system and time series database for Cloud Native applications. Jérémy Decool made a series of great contributions that add support for Prometheus to the Mercure hub. Metrics include (among other things) the number of currently connected subscribers, the number of dispatched updates, the number of served HTTP request segregated by status code, the memory usage, the current number of processes and the number of open file descriptors!

In addition, a new URL (/healthz) is now available to check if the hub is up and running without polluting the HTTP logs with useless entries. This particularly useful for Kubernetes’ liveness and readiness probes.

Version Flag

Jérémy Decool also contributed a new --version flag allowing to know what exact version of the Hub is being used. It looks obvious and priceless, but it was a missing feature. Thanks Jérémy for adding it!

Examples and Demos

We updated the documentation as well as all existing examples (in various programming languages) to be in sync with the latest version of the spec. I also added examples and demos illustrating new features, including a chat written in JavaScript and Python:

This demonstration chat is now available online, try it!

Community

Mercure is becoming more and more popular! It recently reached 2k stars on GitHub and integrations with existing ecosystems are now plenty. For this new version, we worked with the community to keep libraries and other Mercure-related projects in sync with the latest changes in the spec. Most of them are already compatible including (but not limited to):

For some others (for instance, the Java library and the Python library), Pull Requests are open. Finally, some tools still need to be updated including the awesome alternative Hub written in Node created by Nicolas Coutin and the Yii framework integration. Any help is very welcome!

To keep up with Mercure news, you can now follow our brand new Twitter account.

Finally, I’m very happy to announce that Les-Tilleuls.coop now provides official training for Mercure, in English and in French!

Improving Libraries Used by Mercure

One of the most powerful feature of Mercure is the ability to use URI templates to subscribe to topics matching patterns. Under the hood, the reference implementation of Mercure use the uritemplate Go library.

The performance of the Mercure hub highly depends of the performance of this library. So I worked with Kohei Yoshida (the author of this lib) to improve its performance, add benchmarks and fix some bugs! This also dramatically improved the performance of the hub (and of other projects using this library). Thank you Kohei for your quick reviews and releases!

The development of the new version of the hub also allowed me to find an issue in the Go standard library, and to open a Pull Request to fix it.

Hosted and High Availability Versions

Managed and On Premise High Availability (cluster) versions of the Mercure hub are available for a while now. They are already compatible with Mercure 0.10 and are now out of beta!

I want to thank very much our first customers, who trusted us, helped us to battle-test our hosting platform and gave us incomparable feedback allowing us to improve both the open protocol, the Managed and On Premise versions and the Open Source hub! They also allow us to invest more in the protocol’s development and in the Open Source version! So thank you again.

I also want to thank very much my GitHub sponsors, who allow me to work always more on my free software projects, including Mercure but also Vulcain, API Platform and the Symfony components I maintain.

Try and Star Mercure!

If you aren’t using Mercure yet, you can install a hub in a few seconds, or use the online demo, give it a try! If you like the project, show your support by starring it on GitHub!

Vulcain: HTTP/2 Server Push
 and the rise of client-driven REST APIs

Over the years, several formats have been created to fix performance bottlenecks of web APIs: the n+1 problem, over fetching, under fetching…
The current hipster solution for these problems is to replace the conceptual model of HTTP (resource-oriented), by the one of GraphQL.

It’s a smart network hack for HTTP/1… But a hack that comes with (too) many drawbacks when it comes to HTTP cache, logs, security…
Fortunately, thanks to the new features introduced in HTTP/2 and HTTP/3, it’s now possible to create REST APIs fixing these problems with ease and class.

Vulcain is a brand new Internet Draft allowing to create fast, idiomatic and client-driven REST APIs.
To do so, it relies on the Server Push feature introduced by HTTP/2+ and on the hypermedia capabilities of the HTTP protocol.

Better, Vulcain comes with an open source reverse proxy that you can put on top of any existing web API to instantly turn it into a Vulcain-compatible one!

HATEOAS is back, and it’s for the best!

Forum PHP 2019: Mercure – Real-Time for PHP Made Easy

Yesterday at Forum PHP 2019 I presented how easy it is to create real-time apps using PHP (among other languages) and the Mercure protocol.

I also introduced the shiny and new Mercure website (designed by Laury S.)!

A special thanks to Eric Comellas who jumped on stage to explain how iGraal uses Mercure on a large scale to serve simultaneously more than 100,000 of their customers!

API Platform 2.5

API Platform 2.5: revamped Admin, new API testing tool, Next.js and Quasar app generators, PATCH and JSON Schema support, improved OpenAPI and GraphQL support

I’m very excited to announce the immediate availability of API Platform 2.5!

API Platform is a set of standalone server and client components for building and consuming REST (JSON-LD, Hydra, JSON:API…) and GraphQL APIs. The server components use PHP and Symfony while the client-side components (which support any Hydra-enabled web API, even the ones not built using API Platform) are written in JS. If you haven’t tried API Platform yet, it only takes a few minutes to create your first project!

API Platform 2.5 is the best version ever of the framework! Let’s discover its most interesting new features.

API Platform Admin 1.0: the power of React Admin and Material UI unleashed!

API Platform comes with a powerful component to create admin interfaces. It is built on top of React Admin and Material-UI.

Pass the URL of any Hydra-enabled API (including, of course, APIs built with API Platform itself) to the HydraAdmin component, and you instantly get a beautiful, fully-featured admin interface for resources exposed by the API including:

  • CRUD pages;
  • widgets based on the type of the properties;
  • filters;
  • sorting;
  • client-side validation…

The admin interface is dynamically built client-side, by parsing the Hydra metadata of the API. To do so, only a single LLOC is necessary:

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

export default () => <HydraAdmin entrypoint="https://demo.api-platform.com"/>

And you get this (live demo):

demo-admin.api-platform.com

In previous versions, customizing the UI wasn’t straightforward nor idiomatic: you had to post-process the JS object containing the parsed API documentation.

Luckily, the Marmelab (creator of React Admin) and Les-Tilleuls.coop (creator of API Platform) teams got together several times during the summer to create a new version which dramatically improves the DX. Thus API Platform Admin 1.0 was born! While keeping the simplicity of previous versions, it now allows to leverage the power of JSX to customize every part of the UI using React Admin components, Material-UI components, or your custom React components:

import React from "react";
import {
  HydraAdmin,
  ResourceGuesser,
  CreateGuesser,
  InputGuesser
} from "@api-platform/admin";
import { ReferenceInput, AutocompleteInput } from "react-admin";

const ReviewsCreate = props => (
  <CreateGuesser {...props}>
    <InputGuesser source="author" />
    <ReferenceInput
      source="book"
      reference="books"
      label="Books"
      filterToQuery={searchText => ({ title: searchText })}
    >
      <AutocompleteInput optionText="title" />
    </ReferenceInput>

    <InputGuesser source="rating" />
    <InputGuesser source="body" />
  </CreateGuesser>
);

export default () => (
  <HydraAdmin entrypoint="https://demo.api-platform.com">
    <ResourceGuesser
      name="reviews"
      create={ReviewsCreate}
    />
  </HydraAdmin>
);

In the previous example, we add an autocomplete input for a relation by using the dedicated React Admin component while letting API Platform Admin guess which inputs to use for the other properties based on the API docs.

Check out the updated and improved documentation to learn more about these new customization capabilities!

This feature has been contributed by Morgan Auchede, Florian Ferbach, Gildas Garcia, Alexis Janvier, Jean-François Thuillier, François Zaninotto and myself.

Next.js and Quasar support in the Client Generator

API Platform also provides an app generator supporting React, Vue and React Native. And in version 2.5, it is also able to generate high quality Next.js and Quasar apps!

API Platform Client Generator is very similar to Symfony’s MakerBundle and to Rails’ scaffolding, but instead of generating server-side code, it generates a client-side app which uses the API to fetch and persist data. To do so, like the admin component, the generator uses the Hydra specification exposed by the API (built with API Platform or otherwise; support for OpenAPI and GraphQL is in progress).

Next.js is the most popular framework for React, with automatic Server-Side Rendering support, routing, code splitting, CSS-in-JS, static exporting… The Next.js generator, created by Grégory Copin, leverages the 0-config TypeScript support introduced in Next 9: all generated code is written in TS!

To generate a Next app from any API exposing a Hydra specification, run the following commands:

$ npm install next --save # Install next
$ npx @api-platform/client-generator https://demo.api-platform.com src/ --generator next # Scaffold the app

And you get high quality code you can customize to fit your needs:

List screenshot

Refer to the dedicated documentation to learn about all the capabilities of this generator.

Quasar is a framework built on top of Vue.js allowing to write SPAs with Server-Side Rendering support, mobile apps and Electron apps in one go. Its comes with a nice Material Design interface.

To use it, run the following commands:

$ npm install -g @quasar/cli
$ quasar create my-app
$ npx @api-platform/client-generator https://demo.api-platform.com src/ --generator quasar my-app/src # Scaffold the app

A big thanks to Paul Apostol for contributing this generator!

A brand new test client and dedicated API assertions

Currently, there is a lack of satisfactory solutions to write functional tests for web APIs built in PHP (API Platform and Symfony included):

  • Behat+Behatch+Mink is BDD-oriented (which is completely fine, but doesn’t fit with all projects/teams), is a bit complex to set up, has a high barrier to entry and is still not fully compatible with Symfony 4 (you need to rely on a dev version of Behat). It also lacks some utilities, for database testing for instance.
  • BrowserKit/WebTestCase is dedicated to webpage testing through web scraping (DOM Crawler, CSS selectors, simulation of browser actions such as clicking or reloading a page…). Its API doesn’t fit well with API testing. However, it benefits from the large ecosystem of PHPUnit, and gives access to numerous functional testing helpers provided by Symfony.
  • External solutions which don’t manipulate the Symfony Kernel (but are true HTTP clients) such as Postman or Blackfire Player require setting up a web server for the testing environment and don’t provide access to the service container (for instance, to test if the database has been updated, or if a mail has been sent).

It’s time to say hi to ApiTestCase, Test\Client and a bunch of new assertions dedicated to API testing (matching a JSON document or a subset of it, checking the status code and headers of HTTP responses, validating against a  JSON Schema…)! This new set of API testing utilities is built on top of Symfony’s KernelTestCase class, and the Test\Client implements the exact same interface as the brand new Symfony HttpClient component.

This new testing tool also plays very well with Alice (a test fixture generator having an official Symfony/API Platform recipe), which has also gained new powers in the process!

Let’s see how it looks:

namespace App\Tests;

use ApiPlatform\Core\Bridge\Symfony\Bundle\Test\ApiTestCase;
use App\Entity\Book;
use Hautelook\AliceBundle\PhpUnit\RefreshDatabaseTrait;

class BooksTest extends ApiTestCase
{
    // This trait provided by HautelookAliceBundle will take care of refreshing the database content to a known state before each test
    use RefreshDatabaseTrait;
    
    public function testCreateBook(): void
    {
        $response = static::createClient()->request('POST', '/books', ['json' => [
            'isbn' => '0099740915',
            'title' => 'The Handmaid\'s Tale',
            'description' => 'Brilliantly conceived and executed, this powerful evocation of twenty-first century America gives full rein to Margaret Atwood\'s devastating irony, wit and astute perception.',
            'author' => 'Margaret Atwood',
            'publicationDate' => '1985-07-31T00:00:00+00:00',
        ]]);

        $this->assertResponseStatusCodeSame(201);
        $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
        $this->assertJsonContains([
            '@context' => '/contexts/Book',
            '@type' => 'Book',
            'isbn' => '0099740915',
            'title' => 'The Handmaid\'s Tale',
            'description' => 'Brilliantly conceived and executed, this powerful evocation of twenty-first century America gives full rein to Margaret Atwood\'s devastating irony, wit and astute perception.',
            'author' => 'Margaret Atwood',
            'publicationDate' => '1985-07-31T00:00:00+00:00',
            'reviews' => [],
        ]);
        $this->assertRegExp('~^/books/\d+$~', $response->toArray()['@id']);

        // This new assertions checks that the returned JSON document matches the JSON Schema generated by API Platform for this resource (also included in the OpenAPI file) 
        $this->assertMatchesResourceItemJsonSchema(Book::class);
    }

    public function testUpdateBook(): void
    {
        $client = static::createClient();
        // findIriBy allows to retrieve the IRI of an item by searching for some of its properties.
        // ISBN 9786644879585 has been generated by Alice when loading test fixtures.
        // Because Alice use a seeded pseudo-random number generator, we're sure that this ISBN will always be generated.
        $iri = static::findIriBy(Book::class, ['isbn' => '9781344037075']);

        $client->request('PUT', $iri, ['json' => [
            'title' => 'updated title',
        ]]);

        $this->assertResponseIsSuccessful();
        $this->assertJsonContains([
            '@id' => $iri,
            'isbn' => '9781344037075',
            'title' => 'updated title',
        ]);
    }

    public function testDeleteBook(): void
    {
        $client = static::createClient();
        $iri = static::findIriBy(Book::class, ['isbn' => '9781344037075']);

        $client->request('DELETE', $iri);

        $this->assertResponseStatusCodeSame(204);
        $this->assertNull(
            // Through the container, you can access all your services from the tests, including the ORM, the mailer, remote API clients...
            static::$container->get('doctrine')->getRepository(Book::class)->findOneBy(['isbn' => '9781344037075'])
        );
    }
}

Check out the full documentation, or the screencast which has been published on SymfonyCasts on this topic.

Improved GraphQL support

The GraphQL subsystem has been dramatically improved in version 2.5. Kudos to Alan Poulain who has done an awesome job maintaining and improving this part, and to Lukas Lücke and Mahmood Bazdar for their great contributions.

The main features of this new version are the customization of queries, mutations and types.

Whenever you need to add your own logic in your schema, you can now add custom properties in your resource’s annotations to do it. For instance to add a custom query:

/**
 * @ApiResource(graphql={
 *     "myShinyQuery"={
 *         "item_query"=MyQueryItemResolver::class,
 *         "args"={
 *             "id"={"type"="ID"},
 *             "isShiny"={"type"="Boolean!"}
 *         }
 *     }
 * })
 */

You only need to define the corresponding resolver and it’s done!

<?php

namespace App\Resolver;

use ApiPlatform\Core\GraphQl\Resolver\QueryItemResolverInterface;

final class MyQueryItemResolver implements QueryItemResolverInterface
{
    public function __invoke($item, array $context)
    {
        // Do what you want!

        return $item;
    }
}

Please refer to the documentation for customizing the mutations and the types.

The new version also comes with:

  • a better pagination mechanism (including backwards pagination)
  • a new “stage” mechanism allowing to easily customize the built-in resolvers, and an easier way to customize behaviors using decoration
  • support for GraphQL Playground, in addition to GraphiQL
  • a new command to export the GraphQL schema automatically generated by API Platform
  • support for file uploads
  • support for name converters
  • improved overall performance

All these new features have been documented, check it out!

JSON Merge Patch Support

Until now, API Platform had only supported using the PUT HTTP method for replacing a resource. Supporting proper partial updates through the PATCH method is known to be hard.

In version 2.5, a large refactoring work has been done to properly support the PATCH method, and support for JSON Merge Patch (RFC 7386) has been added (to do so, we’ve contributed the required low-level brick to the Symfony Serializer component). The new infrastructure is designed to support other PATCH formats as well. In the future, other formats such as JSON Patch (RFC 6902) may be added.
The JSON:API PATCH format, which was already supported, is of course still working.

Read the dedicated documentation entry to learn more about API Platform’s PATCH support (including how to enable it for existing projects).

JSON Schema Support

JSON Schema is a popular vocabulary to describe the shape of JSON documents. A variant of JSON Schema is also used in OpenAPI specifications. As of API Platform 2.5, JSON Schema is a first-class citizen. A new infrastructure has been created to be able to generate JSON Schemas for any resource, represented in any format (including JSON-LD). A command has also been added to export these schemas:

$ bin/console api:json-schema:generate 'App\Entity\Review'

The generated schema can be used with libraries such as react-json-schema-form to build forms for the documented resources, or to be used for validation.

To generate JSON Schemas programmatically, use the new api_platform.json_schema.schema_factory service.

Improved OpenAPI support

Thanks to the improvements made in the OpenAPI v3 specification, and to the new JSON Schema infrastructure in API Platform, the generated OpenAPI documentation is now better. It generates a specific JSON Schema per supported format:

JSON-LD specific keys such as @id and @context are now documented.

Grégoire Hebert added the ability to configure the versions of OpenAPI to support, while also  allowing to specify the default version being used:

api_platform:
    swagger:
        versions: [3, 2] # OpenAPI v3 is now the default

Frédéric Barthelet and Ryan Weaver improved the OpenAPI documentation of the built-in order and property filters. Thank you!

Screencasts and improved docs

We are very proud to announce an official partnership between API Platform and SymfonyCasts! SymfonyCasts has published more than 7 hours of high quality and funny video tutorials on API Platform (and counting!). The screencasts are now available directly from the main menu of the website, and referenced in the appropriate documentation entries.

Also, for version 2.5, API Platform’s docs have been dramatically improved. All new features presented in this post (and more) are now documented; many parts of the docs have been fixed, improved and modernized; sections have been reordered to provide a better learning experience; and a new “extending API Platform” entry has been added to centralize how to hook your custom logic in a way which is compatible with both the REST and GraphQL subsystems. But there is still a lot to do, and your help is very welcome!

Community milestones and Hacktoberfest

The main strength of API Platform is its vibrant and diverse community! Recently, the project reached great milestones thanks to the many contributors, evangelists and users improving and promoting the framework: the Slack channel reached 2 000 users a few days ago; the core package of the framework has been downloaded more than 2 000 000 times; and workshops, meetups and talks about the project are being organized all over the world (next big events with API Platform talks: Forum PHP Paris and SymfonyCon Amsterdam)!

The framework is close to reaching 5 000 stars on GitHub! It will be the next big milestone, and we’ll organize a big party to celebrate! If you have not starred API Platform yet, please do! It will help us reach a wider audience. If you love the project, tell your friends about it!

Speaking about community, free software and contribution, Hacktoberfest is about to begin! Hacktoberfest is an event helping free software projects by encouraging contributions (code but also docs and marketing materials). As thanks for your contribution, Digital Ocean offers a limited-edition t-shirt, and nice stickers. This year, Les-Tilleuls.coop will also send you some surprise gifts if you contribute at least 3 Pull Requests on the API Platform repositories. Thanks Les-Tilleuls!

Hacktoberfest is a very good opportunity to start contributing to free software, and to API Platform in particular. To help you get started, we’ve marked some code and docs issues with a specific “Hacktoberfest” label:

If you need help working on this, don’t hesitate to ask us directly on GitHub, or in the API Platform Slack channel!

https://lh3.googleusercontent.com/-6RjHzvBuxFo/XZH8jV3YDtI/AAAAAAAADWE/kMKfpexyNWMGC3JMgv0Gp4XfDZxghfe-ACK8BGAsYHg/s0/Image%2Bfrom%2BiOS%2B%252812%2529.jpg

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…

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!

[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.—