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!
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!
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!
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"/>
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).
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:
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.
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.
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'])
);
}
}
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:
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;
}
}
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:
api_platform:
swagger:
versions: [3, 2] # OpenAPI v3 is now the default
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!
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:
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…
Next.js is a convenient and powerful framework for React. Its main benefit over using React directly is its transparent support for Server-Side Rendering. Material UI is a very popular set of React components implementing Google’s Material Design guidelines.
Both libraries are impressive, but there are some tricks to know to make them playing well together.
Bootstrapping
Setting up MUI in a Next project requires some non-trivial tweaks to Next’s initialization process. Conveniently, Material UI provides a skeleton containing a working Next.js project with Material UI already properly configured. It’s the easiest way to kickstart a new project using both tools, don’t miss it!
# Download the skeleton
$ curl https://codeload.github.com/mui-org/material-ui/tar.gz/master | tar -xz --strip=2 material-ui-master/examples/nextjs
$ cd nextjs
# Install the deps
$ yarn install
# Start the project
$ yarn dev
To learn how to integrate Material UI in an existing project, take a look to pages/_document.js and pages/_app.js they contain most the wiring logic.
Forms
Material UI is especially useful because of the large set of form components it provides. But handling forms with React (and so with Next) is tedious and verbose. My colleague Morgan Auchedé recently told me about Formik. Formik is a tiny yet super powerful library allowing to easily create forms with React. And good news: it plays very well with Next! Here is how a basic login form looks when using Formik:
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:
This form is even less verbose, and is now looking good!
Buttons and Routing
Next.js comes with a nice routing system working transparently regardless if the app is executed client-side or server-side. It’s one of the biggest strength of the framework. However, in Material UI, the Button component is often used to trigger navigation between pages, and using buttons with the Router isn’t very intuitive. Still, it’s easy to do:
import React from "react";
import Link from "next/link";
import Button from "@material-ui/core/Button";
export default MyLink = () => (
<Link href="/pricing" passHref>
<Button component="a">Managed version</Button>
</Link>
);
First, we set the component prop of Button to a. It tells Material UI to use an anchor for this button, instead of a… button by default. Then, we set the passHref prop of the Link element, it hints the Router to pass the href prop to the child component, even if doesn’t look like an anchor. Actually (because of the component prop we set earlier), the grandchild will be an anchor, and Material UI will forward the href prop to it! The rendered a element now has a proper href attribute, both client-side and in the server-side generated HTML. Good SEO, for free!
The same trick can be used with the Typography component:
import React from "react";
import Link from "next/link";
import Button from "@material-ui/core/Typography";
export default MyLink = () => (
<Link href="/pricing" passHref>
<Typography variant="caption" component="a">Managed version</Typography>
</Link>
);
This time, we created a link looking like a caption!
That’s all for today. Have fun with Next and Material UI! For more tricks about JavaScript (among various other technologies), follow me on Twitter!
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):
My company Les-Tilleuls.coop will have a booth during every of these events. Come, and let’s have a chat! Also, I’ll announce my participation to some more events soon, stay tuned!
React ESI 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
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.—
I’m pleased to announce the immediate availability of API Platform 2.4 beta! This new version is a huge one, that comes with a large set of new features.
For newcomers, API Platform is a full-stack framework to develop in a breath high quality API-driven projects. Among other (lower level) libraries, API Platform provides:
To create your initial project, you just have to describe the public structures of the data to expose through the API. API Platform will take care of exposing the web API and bootstrapping the clients to consume it: get started with API Platform.
Version 2.4 introduces a lot of very interesting new features. Here is the curated list:
Read and write support for MongoDB, the reference document database, including a lot of useful filters
Read support for Elasticsearch, the open source search and analytics engine, including filters for advanced search
Automatic “push” of updated resources from the server to the clients using the brand new Mercure protocol
Integration with the Symfony Messenger component to easily implement the CQRS pattern and to handle messages asynchronously (using brokers such as RabbitMQ, Apache Kafka, Amazon SQS or Google PubSub)
Automatic availability of list filters in the React-based admin when a corresponding one is available API-side
Full compatibility with the version 3 of the OpenAPI specification format (formerly known as Swagger), and integration of the beautiful ReDoc documentation generator
With 114 commits and 234 files changed over almost 3 years. This is one of the biggest contributions to the project.
The MongoDB integration relies on Doctrine MongoDB ODM 2.0 (currently in beta). To enable this feature, just install and configure DoctrineMongoDBBundle. API Platform will autodetect it. Then, create a class mapped with MongoDB, and mark it as an API resource:
namespace App\Document;
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
/**
* @ApiResource
* @ODM\Document
*/
class Book
{
/**
* @ODM\Id(strategy="INCREMENT", type="integer")
*/
public $id;
/**
* @ODM\Field(type="string")
*/
public $title;
}
The support for MongoDB leverages the flexibility of API Platform: it has been implemented as a data provider and a data persister. Relations, pagination as well as boolean, date, numeric, order, range and search filters are also supported!
A big thanks to all contributors of this amazing feature, and to Andreas Braun, the maintainer of Doctrine MongoDB ODM, for the in-depth reviews!
Elasticsearch support
Elasticsearch is another very popular open-source data store. It allows to perform full-text searches and advanced analyzes on very large datasets. Orange has sponsored the development of an Elasticsearch data provider for API Platform, as well as some interesting search filters. The implementation has been realized by Baptiste Meyer (API Platform Core Team). Thanks to Orange, this feature is now available for everybody in API Platform 2.4.
To enable and configure the Elasticsearch support, refer to the official documentation. Then, a simple resource class corresponding to an Elasticsearch index is enough to benefit from the full power of API Platform:
namespace App\Model;
use ApiPlatform\Core\Annotation\ApiProperty;
use ApiPlatform\Core\Annotation\ApiFilter;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Bridge\Elasticsearch\DataProvider\Filter\MatchFilter;
/**
* @ApiResource
*/
class Tweet
{
/**
* @ApiProperty(identifier=true)
*
* @var string
*/
public $id;
/**
* @var User
*/
public $author;
/**
* @var \DateTimeInterface
*/
public $date;
/**
* @ApiFilter(MatchFilter::class)
*
* @var string
*/
public $message;
}
Then, you can use an URL such as /tweets?message=foo to search using Elasticsearch.
Keep in mind that it’s your responsibility to populate your Elastic index. To do so, you can use Logstash, a custom data persister or any other mechanism that fits for your project (such as an ETL).
Baptiste also took this opportunity to improve the code handling the pagination. It is now a generic class used by all native data providers (Doctrine ORM, MongoDB and Elasticsearch), that you can reuse in your own.
Mercure is a brand new protocol built on top of HTTP/2 and Server-sent Events (SSE). It’s a modern and high-level alternative to WebSocket (WebSocket is not compatible with HTTP/2). Mercure is especially useful to publish updates of resources served through web APIs in real time. It is natively supported by modern browsers (no required library nor SDK) and is very useful to update reactive web and mobile apps.
In version 2.4, I added Mercure support to the server component of API Platform and to the React and React Native app generators. The Docker Compose setup provided with API Platform has also been updated to provide a Mercure hub.
Configuring the framework to automatically dispatch updates to the currently connected clients is straightforward:
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
/**
* @ApiResource(mercure=true)
*/
class Book
{
// ...
}
CQRS and async message handling with Symfony Messenger
Messenger is a new Symfony component created by Samuel Roze (Symfony and API Platform Core Team). It allows to dispatch messages using message queues (RabbitMQ, Kafka, Amazon SQS, Google PubSub…) and to handle them asynchronously. It provides a message bus that is very useful to implement the CQRS design pattern.
In API Platform 2.4, I added a convenient way to leverage the capabilities of Messenger. This new feature is particularly useful to create service-oriented (RPC-like) endpoints:
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @ApiResource(
* messenger=true,
* collectionOperations={
* "post"={"status"=202}
* },
* itemOperations={},
* output=false
* )
*/
class ResetPasswordRequest
{
/**
* @var string
*
* @Assert\NotBlank
*/
public $username;
}
Thanks to the new messenger attribute, this object will automatically be dispatched to the bus. It can then be handled (synchronously or asynchronously) by a message handler:
namespace App\Handler;
use App\Entity\ResetPasswordRequest;
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
class ResetPasswordRequestHandler implements MessageHandlerInterface
{
public function __invoke(ResetPasswordRequest $forgotPassword)
{
// do something with the resource
}
}
HTTP/2 allows a server to pre-emptively send (or “push”) responses (along with corresponding “promised” requests) to a client in association with a previous client-initiated request. This can be useful when the server knows the client will need to have those responses available in order to fully process the response to the original request.
API Platform 2.4 makes it very easy to push relations using HTTP/2:
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiProperty;
use ApiPlatform\Core\Annotation\ApiResource;
/**
* @ApiResource
*/
class Book
{
/**
* @ApiProperty(push=true)
*
* @var Author
*/
public $author;
}
Thanks to the push attribute, if the client asks for /books/1 the web server will directly send both the requested book resource and the related author (e.g. /authors/12) to the client.
The only code that you need to get such UI is the following:
import React from 'react';
import { HydraAdmin } from '@api-platform/admin';
export default () => <HydraAdmin entrypoint="https://api.example.com"/>;
The UI is built client-side dynamically by parsing the API spec. Awesome isn’t it?
Jean-François also added some convenient helpers to help customizing the admin, and Laury Sorriaux fixed a long standing limitation: it’s now possible to use the admin even with API not served at the root of the domain (such as /api).
Also, in addition to Swagger UI, we added support for ReDoc, a beautiful, human-readable, API docs generator written in React:
ReDoc in API Platform 2.4
OpenAPI v3 support has been contributed by Anthony Grassiot (API Platform Core Team). ReDoc integration has been contributed by Grégoire Hébert. A big thanks to them!
Handling Data Transfer Objects was known to be difficult with API Platform. Back in October, the API Platform and the Sylius teams worked together to improve the API of the popular e-commerce solution… using API Platform (stay tuned!). During this workshop Antoine Bluchet and I worked on a new way to handle DTOs with API Platform:
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use App\Dto\BookInput;
use App\Dto\BookOutput;
/**
* @ApiResource(
* input=BookInput::class,
* output=BookOutput::class
* )
*/
final class Book
{
// ...
}
The new input and output attributes allow to use specific classes respectively for the writeable and the readable representation of the resource.
As demonstrated in the example using Symfony Messenger, it’s also possible to set these new attributes to false to hint that the operation will take no inputs or no outputs.
These new attributes are automatically taken into account by all API Platform subsystems, including GraphQL, Hydra and OpenAPI.
use ApiPlatform\Core\Annotation\ApiResource;
/**
* @ApiResource(cacheHeaders={"max_age"=60, "shared_max_age"=120})
*/
class Book
{
// ...
}
With this config, API Platform will automatically generate the following Cache-Control HTTP header: Cache-Control: max-age=60, public, s-maxage=120. Thanks Daniel!