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

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:

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:

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.

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).

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.

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:

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:

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

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:

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!

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:

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…

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!

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:

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:

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:

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!

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.

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

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:

So in light of the NPM malicious code issue that came up this week. We have never seen anything similar in PHP/composer, why? (Poll)

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.

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:

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.

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.

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).

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.

From a few lines of jQuery to modern React/Vue… PWA, Symfony apps always contain JavaScript code. Unfortunately, the SF functional test helper and the Goutte web scrapping lib aren’t able to execute JS code. It means that they cannot assert on client-side generated HTML, test if an element is visible or not, deal with alert boxes or detect if a bug occurs only with a specific browser.

Panther is a brand new e2e testing and web scrapping library written in PHP that drives real browsers thanks to the WebDriver protocol from the W3C. It implements the exact same API than the BrowserKit component. It means than existing SF tests and Goutte scripts work without modification… but this time JS will be executed! The tool also brings new capabilities including taking screenshots, or executing custom JS in the execution context of the web page. To install Panther you only have one command to run, and it doesn’t need any dependency to install Panther. Let’s meet the feline!

During the first presentation of this talk, Panther reached 1,000 stars on GitHub!
To celebrate, I unveiled a set of new features including some brand new database testing helpers inspired from Laravel.

Today, an introduction blog post to Panther was published on the Symfony blog! Panther is a new browser testing and web scraping library I contributed to the Symfony project,
In the blog post, I showcase how to use Symfony, API Platform and VueJS together to create a small but modern app, and how to test it on Panther:

Today, the API Platform framework has reached 3k stars on GitHub, and it makes us very proud! To celebrate, I’ve just tagged the 2.3 version, that comes with a lot of amazing new features. Let’s discover them!

40% faster than the previous version!

We’re committed to continuously improving the performance of API Platform. In version 2.1, we’ve added an amazing invalidation-based cache mechanism. When enabled, HTTP responses are generated only one time then stored and served by a reverse caching proxy. When a resource is modified, all responses including or referencing it are automatically removed from the cache.

A big thanks to Ben and to Nicolas Grekas from Blackfire.io for making it happen!

Support for API evolution (aka deprecating fields and resources)

A growing best practice is to use the evolution strategy for web APIs. Creating new versions of the API, of or its endpoints requires modifying all clients to upgrade, even the ones not impacted by the changes. On the other hand, this strategy (also known as versionless APIs) consists of deprecating the fields, resources types or operations that will be removed at some point. Most modern API formats including GraphQL, OpenAPI and Hydra are able to support this strategy.

In API Platform 2.3, we’ve introduced a new attribute to mark deprecated resource classes, operations and properties. All documentation formats generated by API Platform and having support for this feature will then automatically take it into account.

As you can see, to deprecate a resource, we just have to explain what the client should do to upgrade in a dedicated attribute. You can also use this new deprecationReason attribute on any operation.

The deprecation will automatically be taken into account by clients supporting the previously mentioned format. Here is how it renders for OpenAPI in the built-in Swagger UI shipped with the framework:

All our client-side tools have been updated to ignore deprecated fields, operations and resources by default. The api-doc-parser library (which supports Hydra, and OpenAPI in the latest version) also support this new feature.

Dedicated Profiler Panel and Web Debug Toolbar Integration

Symfony comes with a nice set of development tools, including the Profiler, and it is compatible with API Platform! To install it, execute composer req profiler. Thanks to the contributions of Julien Deniau and Anthony Grassiot, the Web Debug Toolbar now displays an icon featuring our nice spider Webby that is linked to a new profiler panel dedicated to API Platform:

Shorter Attributes Syntax

Defining attributes using annotations can become verbose pretty quickly. As alternatives to annotations, for complex configurations API Platform also supports the XML and YAML formats. However, in version 2.3, Baptiste Meyer added a nicer and shorter syntax to define attributes on the @ApiResource and @ApiProperty annotations:

Of course the “old” syntax is still valid, but the new shortcuts allow a better discoverability and enable autocompletion in IDEs (if you are a PHPStorm user, install the PHP Annotations plugin to benefit from this new feature).

It uses React, and was built on top of the Admin On Rest library. But as you may know, Admin On Rest has been deprecated and Marmelab, the company behind the tool, has released a replacement called React Admin. React Admin comes with an updated fancy interface and it also fixes some design issues.

So we’ve patched API Platform Admin to use the new kid on the block, and we’ve taken this opportunity to also fix a well known annoying issue on our side: the Admin component wasn’t able to deal with embedded relations. This isn’t the case anymore. What’s even better, the Admin is now smart enough to reuse the data already downloaded as embedded relation instead of triggering a new HTTP request. It allows to dramatically improve the performance of the admin!

As usual, thank you very much to all the developers who’ve contributed these new features, bug fixes, and the related documentation entries. You’re the most important part of the project: the community.