Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

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


API Platform is a popular framework to build API-driven projects. The server component is built on top of Symfony. It enables to create modern, extensible and secure web APIs very easily: design the public data model, and that's all, you get a fully-featured API!
But API Platform also provides awesome client-side components (written in JS) working with the server component, and with any other modern REST API! These components include a smart admin builder and client generators supporting React, Vue, React Native, Next, Quasar and Vuetify! Last but not least, API Platform comes with the Docker images and the Kubernetes chart you'll need to deploy in production, in seconds.
Since its introduction during SymfonyLive Paris 2015, API Platform evolved a lot! It is now recognized as the easiest and most powerful set of tools to build and use new web APIs, even outside of the PHP world. During this talk, will discover the new best practices and the unknown gems provided by the framework.


Hi, everybody, let's talk about the new features of API platform. API Platform is a full stack framework for API driven Web projects. Some key points: API Platform lets you building projects very easily, even if you're not an API specialist.
Even if it is very easy to use, it supports by default and without efforts the most modern API technologies.

By default, it will expose an hypermedia API, Mercure to push data from the server to the clients, it supports Vulcain to preload relations of your resources.
It supports the GraphQL format from Facebook. API Platform is a full stack framework. It contains a library to create your API servers, but it also contains libraries written in JavaScript to consume the API, to build Web applications, to build native mobile applications, to build Internet of Things (IoT) devices.

Finally, API platform contains the recipes to deploy this project, both the server side and the frontend parts in production, in your own servers or in the cloud. Even if it is focused on being very easy to use, API Platform is customizable, extensible, modular, you can tweak, replace, change everything and you can very easily plug your own custom business logic.

So the main components of API Platform are the API component, so it's the most popular one, it’s a PHP library and some integrations with popular other PHP libraries allowing to build APIs with ease. There is also the Schema Generator component. So this one is probably the less popular component in the API platform ecosystem. But it's my favorite and actually it deserves a whole talk. Basically, it allows to use definitions of public vocabularies and public schemas for instance Schema.org or, I don't know, the the public data model of the European Union and to generate code and PHP classes and an API Platform API, from these public RDF descriptions.
There is also JavaScript components allowing to create frontend applications, consuming and creating APIs. There is an admin component that is similar to Sonata or EasyAdmin, but this component is written entirely in JavaScript with the React Library. So it has a very nice user experience and it is totally dynamic. You just load a single React component and this component will find the description of your API. It can be an Hydra or an OpenAPI description. It works with any API, with a proper machine-readable documentation and dynamically it will be the screens of the administration and it is fully customizable, it’s a very nice tool. And finally, we have a code generator called the Client Generator component, and it works a bit like the admin component. It will find the description of the API and it will allow us to generate code from this description.

So how to build an API Platform project? First, you will design the public shape of your API, the resources how they are organized, the types, their properties, their relations. So basically you will think about how the clients developers will use your public API, then API platform will give you all the infrastructure to create an API implementing this public data model. It will also generate automatically the documentation, the API documentation and it will provide you a lot of features like the ability to add security rules, access control rules, the user system and things like that.
At this point, you have your server-side API ready. So you can consume this Web API using the client site tools provided by API Platform, the client generator. This tool can generate native mobile apps, Progressive Web Apps, a lot of things like that, and the admin generator. We also provide tools to write automated tests, both server-side and client-side. And finally, we provide a Kubernetes chart and a Docker Compose set up to deploy your application in production. So I think that most of you already used or at least tried API Platform, but let's remember the basics of how it works and the design of the tool.

So first, you need to install the project. So there are several ways to do it, but the easiest way is to go on the API platform website, download the archive, type docker-compose up and everything configured for you, you don't even need to have PHP or a database installed locally, you have a working project. All the configuration required is directly in this template directory that you have download from the API Platform website. And so you must design your public data model. API Platform is both a design-first and a code-first framework. So the mental process of building an API with API Platform will start with a design first approach. So you will describe the shape, the structure, the shape of the resources that you will expose through your API as a set of plain old PHP classes. But these classes are mostly structured and it could be YAML files like with OpenAPI. It could be just a documentation explaining how it should look. It's just a way to encode the public data structure of the API using the PHP language.

So these classes representing the public shape of your API will act as Data Transfer Objects. So API Platform will use these objects to store the data that will be sent to the clients and encode these objects as JSON and bring back the data put by the clients to the server, and extract the content from the JSON documents, hydrate the Data Transfer Objects and give them to you to use them in your business logic. So as we use PHP classes to design the API, we of course can use the full expressivity of the PHP language and use types and also use the PHP documentation to add human readable documentation. So here is a basic example of how to use API Platform, so in this example, we describe a book class. So it will be basically a Book document encoded in JSON in our API. We use the types to describe the types of the properties. We set the constructor to tell that the object must have an ID and a title to be constructed.

We had some PHPDoc and to hint API platform that this class is a special one that describes a public data model. we mark it with the @ApiResource annotation. And that's all. Just with that we get a fully, almost fully working API. The standard REST routes are automatically registered just by using the metadata, provided in the PHP class.

A machine-readable API documentation is generated, actually several formats are supported. By default the OpenAPI format will be used as well as the Hydra documentation format. And you can also enable the GraphQL support if you want to generate a GraphQL Schema. API Platform is also able to generate JSON Schemas.

And in addition to this machine readable documentation, we provide some tools, for instance Swagger UI to display them, to display these documentations for humans. There is only two things that you need to do, API Platform provides all the infrastructure to build modern APIs, but the domain, the business logic, is your own and you have to write it. So API Platform provides extension points you have to use to plug in your domain, your own business logic. There are several interfaces to implement and then everything is wired automatically thanks to the autowiring feature of Symfony.

First, you need to write a Data Provider, the data provider will have to fetch the data from your persistence system, from your database.

You can use, for instance, the Doctrine ORM, or MongoDB, or Google Firebase, everything will n OK, and you fetch the data, you hydrate our DTOs and you return our DTOs. A collection for the lists, an item for the single endpoints. The supports methods allows to check which classes are supported by this data provider, because you can have as many data providers as you need. For write requests, it's almost the same thing, you have another interface to implement, the Data Persister interface and the data you sent to the API will be passed as an argument of these methods so for POST, PATCH, PUT methods, you will have to implement the persist method to fetch the data from the DTO and save it in your database or something like that. And for a delete request, then you will have to remove this, the passed object. The supports method is the same as for the data providers. Data providers and data persisters work both for REST formats and for GraphQL. So with these two classes you have support for REST and GraphQL with the same code.

And just with that, you can use all the features of API Platform, including authorization and authentication data validation, pagination, filtering, sorting realtime push using the Mercure protocol, Vulcain, you get native support for a lot of documentation UIs, including including Swagger UI, Redoc, Graphiql. You have all the tools you need to write your automated tests. You have natively an hypermedia API. You have native support for HTTP/3, for the RDF standards, for GraphQL, for other community formats such as JSON:API, HAL, JSON Schema, just because API Platform provides you all the needed infrastructure. API platform also comes with a Symfony Integration's because, after all, it's SymfonyCon and both projects are very close and related and both core teams are working a lot together. So the core library is the main PHP library of API Platform, and it's a standalone PHP library built on top of Symfony components. Then you have the Symfony Bundle called ApiPlatformBundle, which is shipped with Symfony when you install API Platform by default and it contains all the integrations with Symfony, for instance Routing, the Serializer and things like that.

There are also optional bridges, one for Doctrine, one for MongoDB and one for Elasticsearch. If you use these bridges, then the persistance will be handled automatically for you by API Platform. It's totally optional. It's maybe not what you need, but it's very practical for small APIs, for prototyping and for Rapid ApplicationDevelopment. For instance, if you want to share the public data model of the API with your internal database data model, then you can map the same class with @ApiResource and as a Doctrine entity with the Doctrine annotation and then, automatically, the persistence and the querying is handled for you. And you get a lot of features, including native filters, something automatic pagination and a lot of things. But keep in mind that it's totally optional. Another very interesting feature provided by API Platform, the integration with MakerBundle. So with this tool, you can write your fully working Web APIs, supporting most modern formats without coding at all. So you run the make:entity command and you get an interactive form where you can describe the public data model of your API, the name of the resources, the name of the properties, their types, the relations between the resources and the all the PHP is generated for you with both the API Platform and the Doctrine mapping. So when the command ends, you have a working API. And it is very practical for prototyping.

So let's speak about the very new features of API Platform. I use a very specific methodology for the open source projects I work on. I called that Conference Driven Development. Basically, it means that I submit abstracts to some conferences and sometimes one of these abstracts is selected. And then what is described in this abstract must be implemented. So I have some weeks to implement it. And of course, it's what I've done today for this talk.

The last stable version of API Platform, the last minor version is one year old. It was API Platform 2.5. And as you can see in the screenshot, in one year, a lot of work has been done by the community working on API Platform and especially the core repository.

So for SymfonyWorld, I'm very happy to announce the immediate availability of API platform 2 6 alpha version. It is out. It has been released a few hours before the conference. So you can try everything that I will show right now, just now. So let's start with the new features introduced in the core library. First, we have support for PHP 8, and especially for PHP 8 attributes. So it has been released the past week. And instead of the ugly annotations that we were using, now, with API Platform 2.6, you can use the #ApiResource attribute, for instance, and add native support. for this brand new feature. The constructor is using another new feature of PHP 8 called constructor promotion, basically with the syntax, the arguments of the construct method are also public properties for this class. So it has been a tedious work and there are still some some specific annotations to convert in PHP 8 attributes, but the most common annotations in API Platform can now be used with PHP 8 attributes.

Another very interesting feature in API Platform 2.6 is the ability to define a default configuration that will be applied to all operations and all resources, for instance, in this example, I said that I want to enable only to GET operation for all resources. So with this setting, you don't have to set that you only want to enable to get some every classes as before. It will be the default, and it will be enabled automatically. So this setting this API is read-only. Of course, if you you can override the configuration by putting the specific attribute in the #ApiResource attribute or annotation on a specific resource. So this future is a very good improvement in terms of usability.

Another very nice feature is the ability to add access controls to properties. Access controls for resources were supported from a long time, but it wasn't possible to say, OK, I want to serialize some properties only for the admins, for instance. Now it's supported. So you can use the expression language component of Symfony to tell that, for instance, this property must be serialized only for admins, and other people will not see it.

A lot of work have been done in this Core PHP library. So, for instance, we fixed all depreciations regarding PHP 8. So the library is now fully compatible with PHP 8.
Support for GraphQL subscription: the ability to send updates to clients when something changes to the site has been added and it's using Mercure.
Mercure support for MongoDB has been added.
Support for the new Symfony Serializer annotations @Ignore and @SerializedName has been done. A new builder has been created for the OpenAPI documentation, allowing to customize the output of the OpenAPI documentation very easily. Better support for composed identifiers has been merged to, and we have now an improved support for the Vulcain protocol.

Now let's talk about the other tools in API Platfotm. So the client generator is a JavaScript application allowing to scaffold applications, by parsing an API documentation. It can work with any API even if it's not an API using API platform. If this API as an Hydra documentation or an OpenAPI documentation, you can use this tool.

This tool has a system of skeletons so it's very easy to add support for a new JavaScript framework, so actually you can generate any code in any language. Basically, these generators will have the representation of the structure of the API passed, and then it will be able to generate code by using that.

In 2.5, we had support for generating TypeScript model definitions from the API documentation. For generating Progressive Web Apps using React and Redux, but without Server-Side Rendering. Support for Vue.js. For React Native to build native mobile apps and for the Quasar and Vuetify frameworks that are JavaScript frameworks built on top of Vue.js.

In API Platform 2.6, I am very proud to announce the immediate availability of a new generator for the very popular Next.js framework. Next.js is a very easy to use framework for React. And this framework has support for Server-Side rendering. It means that when using Next.js the same JavaScript code will be executed / can be executed / in the browser and server side with Node. So there is no search engine optimization problems anymore by using this technology.

So Next.js is a very nice tool and we have a generator allowing to generate a fully working Next.js app just from your API documentation now in API Platform. And the generator is now the default one, when you install API Platform by downloading it from the official website, you get a container with a proper Next.js installation and the generator to scaffold your Next application. How does it works? You just run the generate-api-platform-client command. You can pass the URL of the API if it's not the default one if you want and you get all the JavaScript code generated for CRUD applications using the API and Next.js. We also added support for the Nuxt.js framework. It's more or less the same kind of tools as Next.js, but using Vue.js so you can choose your preferred JavaScript too.

We also improved a lot the API Platform developer experience. In 2.5, when you run docker-compose up you get all these services: a service specific for TLS support and HTTPS / HTTP/2. Mercure, Vulcain, and NGINX server, one server for the client, one server for the admin, the database and PHP.

So it's a lot, it works, but it's a lot to learn. It can be hard to deploy if you have some specific setups, when something goes wrong, when you want to fix something. There are a lot of moving parts.

So in API Platform 2.6, we change that to use the Caddy Server. Cady is a very popular Web server, allowing to use modules to do everything that is needed in a modern Web application. So Caddy is a very fast web server written in Go, it’s fully open source, it is built from the ground up to be extensible. It have native support for PHP, it’s just one line of command, it has native support HTTPS and it will use Let’s Encrypt to generate the certificate automatically and it can even generate the certificate on localhost. It has support for HTTP/3, it is cloud native and there's a lot of cloud related features.

Caddy has almost everything needed by API Platform, except a Mercure module, a Vulcain module, and a good Varnish-like HTTP cache module. So I created the Mercure module. And the Vulcain module. And I'm working on a brand new HTTP cache module for Caddy. It's working, but it's still early in the early stages. So now in API Platform, you just have to mandatory services: PHP and Caddy server, with all the modules. There is still Postgres - it’s optional - and there is only one JavaScript container containing Next.js and the admin interface. They are in the same image.

If you don't want to use JavaScript, then you just need the PHP library. There is also Symfony Dockr. It is the same thing. It's also based on Caddy; but it provides only PHP and Symfony. No Postgres, no API Platform, no code.

If you want to add support for Postgres and the ORM, you can use the new Flex support for Docker and you type « docker-compose exec php composer req orm » and Flex will automatically add a Postgres service to your docker-compose.yaml file and install the Postgres driver. Then you can install API Platform like on any Symfony project using composer.

And if you don't want to use Docker at all, you can just download the proper Caddy binary and you can even build your own and cherry pick the modules you want.

I also published a new component called ActivityPub Component. So if you are interested in the Web decentralization and the ability to fight against the censorship promoted by Facebook, Twitter and most major tech platforms, you can take a look at my talk « save the web, decentralize » and you will learn that the W3C is promoting a new protocol allowing to build decentralized social networking applications. It’s called « ActivityPub » and a lot of software already implement it, including Mastodon, PeerTube, PixelFed, Mobilizon and a lot of other tools that can work together using this protocol.

If you want to build such applications, now you can use the API Platform ActivityPub Component. You can install it on any Symfony or API Platform project and it adds support for this protocol for your own social network application built in PHP and with Symfony.

Finally, everything in API Platform is only possible because of the community. We have a lot of contributors working on the code but also on the documentation and support and making talks and YouTube videos… We have a very nice sponsor paying for a large part of the development, which is Les-Tilleuls.coop.

So to thank the community, we added new pages on the website showcasing the work of the contributors. So now everybody, each API Platform contributor has a dedicated page with the list of his/her contributions and a link to his/her GitHub profile, and to his/her personal website. Also for people having contributing during Hacktoberfest, drop us a mail, because we will send you a T-shirt.

Just one more thing, the next release of API Platform after 2.5 will be API Platform 3. API Platform 3 will support only PHP 8. It will have better support for subresources. There is an ongoing refactoring, subresources first class citizen in API Platform 3 and you will be able to have write support for subresources.

API platform 3 will be the same code that API Platform 2.7 but without the backward compatibility layer. So both API Platform 3 and 2.7 will be released at the same time, like Symfony 4.4 and 5.0.

If you like my work if you like this talk, if you like API Platform, don't hesitate to sponsor me on GitHub it helps me working more on this kind of talks but also on the maintenance and on the new feature of the framework.

Thank you very much. And if you have some time, please download and test API Platform 2.6 alpha on your own projects so we can find and squash bugs. Thank you very much.

Kévin Dunglas

December 03, 2020

More Decks by Kévin Dunglas

Other Decks in Programming


  1. None
  2. API Platform : The API-first Framework

  3. @dunglas API Platform: key points A rock-solid API-first project in

    minutes State-of-the-art API technologies:
 hypermedia, Mercure, Vulcain, GraphQL … Batteries included:
 create (server), consume (clients) and deploy Customizable, extensible, modular
  4. Main components

  5. None
  6. Getting Started

  7. @dunglas Docker All you need is (and it’s optional)

  8. @dunglas Install Download the latest release on api-platform.com https://localhost $

    docker-compose up
  9. The basics

  10. @dunglas Design AND Code First Design the public data model

    exposed by your AP I Describe it as a set of Data Transfer Objects (DTO ) Add types Embed human-readable docs
  11. @dunglas Design AND Code First namespace App\Entity; use ApiPlatform\Core\Annotation\ApiResource; /**

    * A book * * @ApiResource */ class Book { /** Identifier of the book */ public string $id; /** Title of the book */ public string $title; public function __construct(string $id, string $title) { $this->id = $id; $this->title = $title; } }
  12. Standard REST routes ar e automatically registered

  13. Machine-readable API docs are dynamically generated from PHP class metadata

    : ❏ Hydra / RD F ❏ OpenAPI v2 (aka Swagger) and v 3 ❏ GraphQL schem a ❏ JSON Schema
  14. @dunglas Plug your domain: read class BookDataProvider implements /* Item|Collection|…

    */DataProviderInterface { public function getCollection(string $resourceClass /*…*/): iterable { // Return the collection of Book objects (can be a paged collection) // matching the passed criteria } public function getItem(string $resourceClass, $id /*…*/): Book { // Return the Book object having this ID } public function supports(string $resourceClass /*…*/): bool { // Register as many data providers as needed return $resourceClass === Book::class; } }
  15. @dunglas Plug your domain: write class BookDataPersister implements /*…*/DataPersisterInterface {

    public function persist($data /*…*/) { // Extract the data from the DTO and use it } public function remove($data /*…*/) { // Remove this resource } public function supports($data /*…*/): bool { // Plug as many data persisters as needed return $data instanceof Book; } }
  16. @dunglas Enjoy the Built-in Features! Aut h Validatio n Paginatio

    n Filterin g Sortin g Real-time Push: Mercur e Rels preloading: Vulcai n Docs: Swagger UI, Redoc, GraphiQL… Automated test s Hypermedi a HTTP/ 2 RDF / JSON-LD / Hydr a GraphQ L JSON:AP I HA L JSON Schem a …
  17. Symfon y Integrations

  18. @dunglas Available Integrations Core: a standalone PHP lib built on

    top of Symfony Component s Symfony Bundle: Symfony Framework integratio n Doctrine Bridge: automatic persistence with Doctrine ORM (read/write ) MongoDB Bridge: automatic persistence with Doctrine MongoDB ODM (read/write ) Elasticsearch Bridge: ES integration (read-only)
  19. @dunglas Automatic Persistenc e (maybe NOT what you need) /**

    * @ApiResource * @ORM\Entity */ class Book { /* … */ }
  20. @dunglas No Code: MakerBundle

  21. Conference-Driven Development

  22. @dunglas API Platform 2.5: 1+ year old

  23. API Platform 2.6 alph a is out!

  24. Core Lib
 New Features

  25. @dunglas PHP 8 Attributes use ApiPlatform\Core\Annotation\ApiResource; #[ApiResource] class Book {

    public function __construct( public string $id, public string $title, ) {} }
  26. @dunglas Global Defaults Contributed by Benoît Polaszek ❤ # config/packages/api_platform.yaml

    api_platform: defaults: itemOperations: ["get"] collectionOperations: ["get"] mercure: true # This config is applied to all 
 operations of all resources!
  27. @dunglas Access Control For Properties use ApiPlatform\Core\Annotation\ApiProperty; class Book {

    #[\ApiProperty(security: "is_granted('ROLE_ADMIN')"] public $adminOnlyProperty; // Only admins will see the adminOnlyProperty prop } Contributed by Frédéric Barthelet & Grégoire Hébert ❤
  28. @dunglas More New Features Full PHP 8 compatibility ❤ Pierre

    du Plessis, Antoine Bluchet & me GraphQL subscriptions (using Mercure) ❤ Alan Poulain Mercure support for MongoDB ❤ Alan Poulain Support for @Ignore & @SerializedName Serializer annotations ❤ Alexander Janssen, Marcel Malberg & MartkCz Brand new OpenAPI docs builder ❤ Antoine Bluchet Better support for composed identifiers ❤ Antoine Bluchet Improved Vulcain support ❤ Pierre Thibaudeau and many others
  29. Client Generator

  30. @dunglas API Platform Client Generator Scaffolds client apps by parsing

    API doc s Supports Hydra (preferred) and OpenAPI (experimental ) Pluggable skeletons: bring your own ! Works with any APIs (even if not written in PHP)
  31. @dunglas Pre-existing Generators TypeScript model definition s React + Redux

    (no SSR ) Vue.js (no SSR ) React Nativ e Quasa r Vuetify
  32. @dunglas New Generator: Contributed by Grégory Copin ❤ Replace the

    old React/Redux
 generator in the distribution ! No config needed, TypeScrip t Server-Side Renderin g Smart bundling, route prefetching…
  33. @dunglas New Generator: $ docker-compose exec client \ 

  34. @dunglas New Generator: Contributed by Alain Hippolyte ❤ Easy to

    learn (good old HTML/JS/CSS ) Server-Side Renderin g Performant $ docker-compose exec client \ 
 generate-api-platform-client \ —-generator nuxt
  35. API Platform UX

  36. It’s the magic of REST’s layer system,
 but this can

    be hard to understand, and hard to manage in prod. + Varnish Cache in pro d
  37. Caddy: Fewer Moving Parts

  38. @dunglas Caddy Web Server Free and Open Source web serve

    r Super fast, written in G o Extensibl e Native PHP FPM support Automatic HTTPS, even for localhos t HTTP/3 ! Cloud native (API, hot config reloading… ) Can be used as a Kubernetes Ingress
  39. @dunglas One Daemon To Rule Them All Caddy had almost

    everything needed by most Symfony / API Platform projects except : a Mercure module (async APIs, push ) a Vulcain module (RESTful relations preloading ) an HTTP cache module
  40. A Mercure Module for Caddy

  41. A Vulcain Module for Caddy

  42. An HTTP Cache Module for Caddy

  43. @dunglas Docker Services in APIP 2.6 PHP FP M Caddy

    server (with all modules ) Postgres (optional ) Node / NextJS (optional ) client and admin containers have been merged in a single React app
  44. What If I Only Use The PHP Lib?

  45. @dunglas Introducing Symfony Docker Same Caddy-based setu p But only

    PHP and Symfony ! No Postgres, no Node
  46. @dunglas New: Symfony Flex’s Docker Configurator $ docker-compose exec php

    \ composer req orm Doctrine, a Postgres service and the pdo_pgsql driver are installed! $ docker-compose exec php \ composer req api API Platform (PHP only) is installed!
  47. @dunglas I Don’t Want Docker At All! A version of

    Caddy, including the same modules as in Symfony's Docker is available as a standalone binary . You can also build your own binary and include only the modules you want: $ xcaddy build \ —-with github.com/dunglas/mercure/caddy \ —-with github.com/dunglas/vulcain/caddy
  48. A New Component : ActivityPub

  49. We Must Save The Web

  50. @dunglas The ActivityPub Protocol A decentralized social networking protoco l

    W3C Recommendatio n Servers are interoperable and can be federated: the fediverse Implemented by Mastodon (Twitter-like), PeerTube (YouTube-like), PixelFed (Instagram- like), Mobilizon (Meetup-like)…
  51. Build Your Decentralized App:

  52. Community

  53. @dunglas Community API Platform exists thanks to its communit y

    590 contributors ❤ code, docs, community support,
 propaganda (aka evangelization) … 6,3K GitHub stars, 5M+ download s ~30 repositories written in PHP, JS, Go, Shell … An awesome sponsor:
  54. A Brand New Community Section

  55. A Page For Each Contributor!

  56. And Even T-Shirts!

  57. API Platform Version 3

  58. @dunglas Next Release: API Platform 3 Upgrade path: API Platform

    3 = API Platform 2.7 minus the backward compatibility layer
 (same as Symfony ) PHP 8 only ! Revamped subresources, with write support Revamped UX
  59. If you like my work,
 consider sponsoring me on GitHub:

  60. test API Platform 2.6 alpha Thank you! @dunglas - api-platform.com