Slide 1

Slide 1 text

Evgeny Smirnov and how to use ( fi rst look)

Slide 2

Slide 2 text

+ Why?

Slide 3

Slide 3 text

+

Slide 4

Slide 4 text

+

Slide 5

Slide 5 text

+ What’s inside?

Slide 6

Slide 6 text

+ Out of the box “CRUD, data validation, pagination, fi ltering, sorting, json/hydra, GraphQL, swagger, CORS, OWASP inside…”

Slide 7

Slide 7 text

+ Follow best practice because you can’t do otherwise

Slide 8

Slide 8 text

+ Getting started 1. Official “Getting started” guide 2. SymfonyCast: RESTful APIs and 
 API Platform guides 3. StackOverflow

Slide 9

Slide 9 text

+ Installation Dockerised distribution 
 (check symfony version) or through symfony

Slide 10

Slide 10 text

+ Why?

Slide 11

Slide 11 text

+

Slide 12

Slide 12 text

+ Custom business logic for any writing action — DataPersisters* * use decorator pattern

Slide 13

Slide 13 text

+ final class UserQuizDataPersister implements ContextAwareDataPersisterInterface { private $decorated; private $security; … public function persist($data, array $context = []) { if (is_null($data->getUser())) { $user = $this->security->getUser(); $data->setUser($user); } $result = $this->decorated->persist($data, $context); return $result; } public function remove($data, array $context = []) { return $this->decorated->remove($data, $context); } } Data Persisters

Slide 14

Slide 14 text

+ Data Providers Here should be an example but I have not used providers…

Slide 15

Slide 15 text

+ Custom action for an action of a resource — Action Controller

Slide 16

Slide 16 text

+ #[AsController] class SkipUserQuestion extends AbstractController { public function __invoke(UserQuestion $data): UserQuestion { $data->setStatus(UserQuestion::STATUS_SKIPPED); return $data; } } Pseudo Controllers

Slide 17

Slide 17 text

+ Various input and output data for the same model — DataTransformer and DTO

Slide 18

Slide 18 text

+ public function transform($data, string $to, array $context = []) { $resetPasswordRequest = new ResetPasswordRequest(); $user = $this->userRepository->findOneByEmail($data->getEmail()); $resetPasswordRequest->setUser($user); $now = new \DateTimeImmutable(); $expiredAt = new \DateTimeImmutable('+1 hour'); $resetPasswordRequest->setRequestedAt($now); $resetPasswordRequest->setExpiresAt($expiredAt); return $resetPasswordRequest; } Data Transformers

Slide 19

Slide 19 text

+ final class ResetPasswordRequestInput { #[Groups(['resetPasswordRequest:create', 'resetPasswordRequest:read'])] #[Assert\NotBlank(groups: ['validation:create'])] #[Assert\Email()] private $email; public function getEmail(): ?string { return $this->email; } public function setEmail(string $email): self { $this->email = $email; return $this; } } DTOs

Slide 20

Slide 20 text

+ … and much more: EventListeners, Subscribers, Filters, async …

Slide 21

Slide 21 text

+ Useful add ons ✅ JWT through LexikJWTAuthenticationBundle ✅ JWT refresh tokens GesdinetJWTRefreshTokenBundle ❌ Complete sign up / sign in ❌ Role based API versions

Slide 22

Slide 22 text

+ Disambiguous?

Slide 23

Slide 23 text

+ PATCH /entity/{id} or PUT /entity/{id}/{custom-action}

Slide 24

Slide 24 text

+ GET /entity/{id}/?{subentity}=% or GET /entity/{id}/{subentity}

Slide 25

Slide 25 text

+ Action-Controller or DataPersister for custom writing logic?

Slide 26

Slide 26 text

+ 4-5 extra classes (DTOs, Transformers, etc.) or Custom controller outside of API Platform* * and extra classes for OpenAPI docs…

Slide 27

Slide 27 text

+ Too many ways how to perform a regular action

Slide 28

Slide 28 text

+ Good for RESTful APIs with regular customisations Bad for custom APIs

Slide 29

Slide 29 text

+

Slide 30

Slide 30 text

+

Slide 31

Slide 31 text

+