1 of 73

SEPTEMBER 21-22, 2023 - LILLE, FRANCE & ONLINE

REVOLUTION

2 of 73

3 of 73

RELEASE CYCLE

  • Minor version is released every six months
  • Major version is released every two years

2.7 / 3.0

3.2

4.x

2021

Today

2024

4 of 73

RELEASE CYCLE

3.0

3.2

4.x

2021

2024

3.1

244 commits

279 commits

cool stuff

3.3

Today

5 of 73

RIP 2.7

  • Only security fixes
  • Maintenance is hard
  • Contact Les-Tilleuls.coop if you need help to upgrade!

6 of 73

Tomorrow at 14:00

7 of 73

3.0

  • Metadata refactoring
  • State providers / processors
  • URI Variables

API Platform is easier to get around, more intuitive and less restrictive

8 of 73

3.1

Deprecations and new features

9 of 73

Standard PUT

The HTTP specification states that PUT requests should create or replace the state defined by the representation enclosed in the request message content.

#[ApiResource(

operations: [new Get(), new Put(allowCreate: true)],

extraProperties: [

'standard_put' => true,

]

)]

#[Entity]

class Book {}

10 of 73

Standard PUT

  • Standard PUT is now the default
  • Non-standard behavior will be removed in API Platform 4
  • Use PATCH (application/merge-patch+json) to do partial updates

# config/packages/api_platform.yaml

api_platform:

defaults:

extra_properties:

standard_put: true

11 of 73

Denormalization Errors

#[ApiResource(

collectDenormalizationErrors: true

)]

class Book {}

If the submitted data trigger denormalization errors, the HTTP status code will be set to 422 Unprocessable Content and the response body will contain the list of errors.

12 of 73

Denormalization Errors

{

"@type": "ConstraintViolationList",

"hydra:title": "An error occurred",

"hydra:description": "boolean: This value should be of type bool...",

"violations": [

{

"propertyPath": "bar",

"message": "This value should be of type bool."

},

{

"propertyPath": "foo",

"message": "This value should be of type string."

}

]

}

13 of 73

OpenAPI

  • Disable OpenApi on an operation
  • Deprecating the array openapiContext in favor of openapi option
  • Use our OpenApi models without the API Platform suite
  • OpenAPI 3.1 + Swagger UI 5!

#[Post(

openapi: false

)]

class Book {}

14 of 73

OpenAPI As Attributes

use ApiPlatform\OpenApi\Model as OpenApi;�

#[Post(

openapi: new OpenApi\Operation(

requestBody: new OpenApi\RequestBody(

content: new \ArrayObject([

'multipart/form-data' => [

'schema' => [

'type' => 'object',

'properties' => [

'file' => ['type' => 'string', 'format' => 'binary']

]

]

]

])

)

)

)]

15 of 73

OpenAPI Component

16 of 73

Subtree Split

  • Standalone mode
  • Split of every core components
  • API Platform without Symfony (Laravel ?)

17 of 73

Resource vs Doctrine Entity

namespace App\ApiResource;

use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;

use ApiPlatform\Doctrine\Orm\State\Options;

use ApiPlatform\Metadata\ApiFilter;

use App\Entity\Book as BookEntity;

#[ApiResource(stateOptions: new Options(entityClass: BookEntity::class))]

class Book

{

public string $id;

#[ApiFilter(OrderFilter::class)]

public string $value;

}

18 of 73

Tomorrow at 09:00

19 of 73

And more…

  • New agnostic Cache Purger interface (with Souin support)
  • Enum support (OpenApi, JsonSchema, GraphQL)
  • JsonSchema assertions now support serialization groups
  • Many components are available as standalone

20 of 73

3.2

Deprecations and new features

21 of 73

Write support on alternate resources!

namespace App\Entity;

use ApiPlatform\State\CreateProvider;

use App\Entity\Company;

#[Post(

uriTemplate: '/companies/{id}/employees',

uriVariables: [

'id' => new Link(fromClass: Company::class, toProperty: 'employee'),

],

provider: CreateProvider::class,

)]

class Employee {}

22 of 73

IRI Customisation

#[GetCollection(

uriTemplate: '/companies',

itemUriTemplate: '/companies/{id}/employees/{id}'

)]

class Company {

/** @var Employee[] */

#[ApiProperty(uriTemplate: '/companies/{id}/employees')]

public array $employees;

}

23 of 73

Today at 17:00

z

24 of 73

URI Variables & Links

use ApiPlatform\Metadata\Get;

use ApiPlatform\Metadata\Link;

#[Get(

uriTemplate: '/book/{title}',

uriVariables: ['title' => new Link(identifiers: ['title'])]

)]

#[ORM\Entity]

final class Book {}

25 of 73

Handle Links

use ApiPlatform\Doctrine\Orm\State\Options;

use Doctrine\ORM\QueryBuilder;

use ApiPlatform\Metadata\Get;

#[Get(

uriTemplate: '/book/{title}',

stateOptions: new Options(

handleLinks: fn(QueryBuilder $queryBuilder, array $identifiers) => {

$queryBuilder->andWhere("{$queryBuilder->getRootAliases()[0]}.title = :title");

$queryBuilder->setParameter('title', $identifiers['title']);

}

)

)]

#[ORM\Entity]

final class Book {}

26 of 73

JSON Problem

  • An Error is a Resource
  • JSON problem (RFC 7807) compliant errors
  • Set the status of an Error on your exception instead of using exceptionToStatus!

# config/packages/api_platform.yaml

api_platform:

defaults:

extra_properties:

rfc_7807_compliant_errors: true

27 of 73

Error Resource

use ApiPlatform\Metadata\ErrorResource;

use ApiPlatform\Metadata\Error;

#[ErrorResource(

uriTemplate: '/my_error/{id}',

status: 418,

openapi: false,

uriVariables: ['id'],

operations: [

new Error(outputFormats: ['jsonproblem' => ['application/problem+json']]),

]

)]

final class MyException implements ProblemExceptionInterface {}

28 of 73

29 of 73

Let’s Go Back In Time…

namespace Dunglas\JsonLdApiBundle\Controller;

class ResourceController extends Controller implements ResourceControllerInterface

{

public function getAction(Request $request, $id)

{

$object = $this->findOrThrowNotFound($id);

return new JsonLdResponse($this->normalize($object));

}

}

30 of 73

Then, Listeners were introduced…

31 of 73

API Platform 2

32 of 73

HTTP Kernel Listeners

API Platform relies on Symfony kernel listeners to handle Validation, Serialization, Security and data persistence.

33 of 73

PATCH /books/1

Content-Type: application/merge-patch+json

{"title": "API Platform"}

Kernel “request”

  • ReadListener
  • SecurityListener
  • DeserializeListener

Kernel “view”

  • ValidateListener
  • WriteListener
  • SerializeListener

34 of 73

Why are listeners not ideal?

  • Strong link with symfony/http-kernel
  • Listeners priorities are not covered by the BC promise
  • Hard to share logic with sub systems like GraphQl
  • Relying on event listeners to extend API Platform is discouraged

I love providers

35 of 73

MainController

<?php

use ApiPlatform\State\ProviderInterface;

use ApiPlatform\State\ProcessorInterface;

class MainController {

public function __invoke(ProviderInterface $provider, ProcessorInterface $processor) {

$body = $this->provider->provide($operation, $uriVariables, $context);

return $this->processor->process($body, $operation, $uriVariables, $context);

}

}

36 of 73

37 of 73

Composition with Providers and Processors

  • ReadListener
  • SecurityListener
  • DeserializeListener
  • ValidateListener
  • WriteListener
  • SerializeListener

ReadProvider

SecurityProvider

DeserializeProvider

ValidateProcessor� WriteProcessor

SerializeProcessor

38 of 73

The Power Is Yours

bin/console debug:container api_platform.state_provider.access_checker

Allows access based on the �ApiPlatform\Symfony\Security\ResourceAccessCheckerInterface.

This implementation covers GraphQL and HTTP.

�Service ID api_platform.state_provider.access_checker

Class ApiPlatform\Symfony\Security\State\AccessCheckerProvider

Usages api_platform.state_provider.access_checker.post_deserialize

api_platform.state_provider.deserialize

api_platform.state_provider.read

39 of 73

Goodbye Symfony Listeners

# config/packages/api_platform.yaml

api_platform:

event_listeners_backward_compatibility_layer: true # will be false in API Platform 4

  • Do not rely on our listeners behavior
  • Request attributes are still used
  • If you need to alter API Platform’s behavior decorate our providers/processors
  • Or create your own API Platform controller

40 of 73

And more…

  • Replace doctrine/inflector by symfony/string

  • Support union/intersect types
  • Elasticsearch 8 compatibility

# config/packages/api_platform.yaml

api_platform:

keep_legacy_inflector: true # will be false in API Platform 4

41 of 73

3.2

Documentation Revolution

42 of 73

New Website!

43 of 73

Open source & Documentation

  • New features not documented
  • Documentation is hard (https://diataxis.fr)
  • We’re lazy developers…

Can we use code as documentation ?

44 of 73

45 of 73

46 of 73

47 of 73

Guides

  • A guide is an executable PHP file
  • It is presented like Literate programming
  • The guide can be tested with PHPUnit

48 of 73

PHP + WASM = ❤️

49 of 73

50 of 73

What’s up next?

How we made API Platform compatible with Laravel 10-13-2023!

51 of 73

Be Ready For API Platform 4!

composer recipes:update

FOLLOW ME!

@s0yuka

soyuka.me

@soyuka@phpc.social

52 of 73

Thank you!

Any questions?

FOLLOW ME!

@JaneDoeTwitter

jane-doe.com

53 of 73

54 of 73

Amazing second part

Interesting introduction

Incredible third part

Another amazing part

A spectacular conclusion

01

02

03

04

05

55 of 73

01 - Interesting introduction

Some cool stuff

56 of 73

About me

Jane Doe

  • Technical director, at some company name
  • Active contributor to API Platform
  • Passionate developer since ten years

57 of 73

About me again

  • Technical director, at some company name
  • Active contributor to API Platform
  • Passionate developer since ten years

JANE DOE

@JaneDoeTwitter

jane-doe.com

58 of 73

Some code

{

"@context": "/contexts/ConstraintViolationList",

"@type": "ConstraintViolationList",

"hydra:title": "An error occurred",

"hydra:description": "isbn: This value is neither a valid ISBN-10 nor a valid ISBN-13.\ntitle: This value should not be blank.",

"violations": [

{

"propertyPath": "isbn",

"message": "This value is neither a valid ISBN-10 nor a valid ISBN-13."

},

{

"propertyPath": "title",

"message": "This value should not be blank."

}

]

}

59 of 73

Some title

Add your text here

60 of 73

Another example

  • You can add stuff here
  • Or here…
  • Or even here!

61 of 73

Another example

  • You can add stuff here
  • Or here…
  • Or even here!

Add something here

62 of 73

Another example

  • You can add stuff here
  • Or here…
  • Or even here!

63 of 73

Another slide

  • You can add stuff here
  • Or here…
  • Or even here!

Example

Some content you want to highlight

64 of 73

Another example

  • You can add stuff here
  • Or here…
  • Or even here!

Another content to highlight

Add caption (or not)

65 of 73

Some title

Add your text here

Say something (or delete this)

66 of 73

Some title

Add your text here

67 of 73

Some title

Some interesting point

Another interesting point

A final interesting point

68 of 73

Some title

Some interesting point

A final interesting point

Another interesting point

69 of 73

You can say interesting

things here

  • Large topics discussed on that wonderful slide
  • You can write something else

Hello!

70 of 73

Thank you!

Hello!

Any questions?

@JaneDoeTwitter

jane-doe.com

Follow me on social media

71 of 73

Thank you!

Any questions?

FOLLOW ME!

@JaneDoeTwitter

jane-doe.com

72 of 73

Need graphic stuff for your slides?

73 of 73

Need graphic stuff for your slides?

Something cool