Slide 1

Slide 1 text

basecom · wir sprechen internet 1 FOSRest 2.0 SymfonyLive, Cologne 2016

Slide 2

Slide 2 text

basecom · wir sprechen internet 2 Christian Flothmann Software-Entwickler bei basecom in Osnabrück - Symfony Core Team - Symfony Documentation Team - Co-Maintainer FOSRestBundle @xabbuh

Slide 3

Slide 3 text

basecom · wir sprechen internet 3 Was ist das FOSRestBundle?

Slide 4

Slide 4 text

basecom · wir sprechen internet 4 • Routengenerierung • Dekodierung von Requestdaten (JSON, XML, etc.) • Content-Negotiation • Serialisierung von Daten für HTTP-Response Tools für

Slide 5

Slide 5 text

basecom · wir sprechen internet 5 Warum 2.0?

Slide 6

Slide 6 text

basecom · wir sprechen internet 6 • gewachsene Codebasis • existierende Extension-Points • PHP 5.3 • Symfony 2.3 • aufwändig neue Features zu implementieren

Slide 7

Slide 7 text

basecom · wir sprechen internet 7 Was gibt es Neues?

Slide 8

Slide 8 text

basecom · wir sprechen internet 8 • Code Cleanup • Container-Klassenparameter entfernt • DI statt Service Locator • Update auf willdurand/negotiation 2.0 • Symfony >= 2.7, PHP >= 5.5.9 • ParamFetcher und Exception-Handling überarbeitet Neu in 2.0

Slide 9

Slide 9 text

basecom · wir sprechen internet 9 HTTP-Methoden nach RFC-2518

Slide 10

Slide 10 text

basecom · wir sprechen internet 10 • COPY • LOCK • MKCOL • MOVE • PROPFIND • PROPPATCH • UNLOCK HTTP-Methoden nach RFC-2518

Slide 11

Slide 11 text

basecom · wir sprechen internet 11 FOSRestBundle 1.7 namespace AppBundle\Controller; class UserController { public function lockUserAction($id) { } }

Slide 12

Slide 12 text

basecom · wir sprechen internet 12 FOSRestBundle 1.7 $ php app/console debug:router lock_user +--------------+------------------------------------------------------------------+ | Property | Value | +--------------+------------------------------------------------------------------+ | Route Name | lock_user | | Path | /users/{id}/lock.{_format} | | Path Regex | #^/users/(?P[^/]++)/lock(?:\.(?P<_format>json|xml|html))?$#s | | Host | ANY | | Host Regex | | | Scheme | ANY | | Method | PATCH | | Requirements | _format: json|xml|html | | Class | Symfony\Component\Routing\Route | | Defaults | _controller: AppBundle:User:lockUser | | | _format: NULL | | Options | compiler_class: Symfony\Component\Routing\RouteCompiler | +--------------+------------------------------------------------------------------+

Slide 13

Slide 13 text

basecom · wir sprechen internet 13 FOSRestBundle 1.7 namespace AppBundle\Controller; use FOS\RestBundle\Controller\Annotations\Route; class UserController { /** * @Route("/users/{id}", methods={"LOCK"}) */ public function lockUserAction($id) { } }

Slide 14

Slide 14 text

basecom · wir sprechen internet 14 FOSRestBundle 1.7 $ php app/console debug:router lock_user +--------------+------------------------------------------------------------------+ | Property | Value | +--------------+------------------------------------------------------------------+ | Route Name | lock_user | | Path | /users/{id}.{_format} | | Path Regex | #^/users/(?P[^/]++)/lock(?:\.(?P<_format>json|xml|html))?$#s | | Host | ANY | | Host Regex | | | Scheme | ANY | | Method | LOCK | | Requirements | _format: json|xml|html | | Class | Symfony\Component\Routing\Route | | Defaults | _controller: AppBundle:User:lockUser | | | _format: NULL | | Options | compiler_class: Symfony\Component\Routing\RouteCompiler | +--------------+------------------------------------------------------------------+

Slide 15

Slide 15 text

basecom · wir sprechen internet 15 FOSRestBundle 2.0 namespace AppBundle\Controller; class UserController { public function lockUserAction($id) { } }

Slide 16

Slide 16 text

basecom · wir sprechen internet 16 FOSRestBundle 2.0 $ php app/console debug:router lock_user +--------------+---------------------------------------------------------------+ | Property | Value | +--------------+---------------------------------------------------------------+ | Route Name | lock_user | | Path | /users/{id}.{_format} | | Path Regex | #^/users/(?P[^/\.]++)(?:\.(?P<_format>json|xml|html))?$#s | | Host | ANY | | Host Regex | | | Scheme | ANY | | Method | LOCK | | Requirements | _format: json|xml|html | | Class | Symfony\Component\Routing\Route | | Defaults | _controller: AppBundle:User:lockUser | | | _format: NULL | | Options | compiler_class: Symfony\Component\Routing\RouteCompiler | +--------------+---------------------------------------------------------------+

Slide 17

Slide 17 text

basecom · wir sprechen internet 17 DirectoryRouteLoader

Slide 18

Slide 18 text

basecom · wir sprechen internet 18 FOSRestBundle 1.7 api_category: resource: 'AppBundle\Controller\CategoryController' type: rest api_post: resource: 'AppBundle\Controller\PostController' type: rest api_post_comment: resource: 'AppBundle\Controller\PostCommentController' type: rest api_user: resource: 'AppBundle\Controller\UserController' type: rest # ...

Slide 19

Slide 19 text

basecom · wir sprechen internet 19 FOSRestBundle 2.0 api: resource: '@AppBundle/Controller' type: rest

Slide 20

Slide 20 text

basecom · wir sprechen internet 20 Vorsicht bei sich überlappenden Routen!

Slide 21

Slide 21 text

basecom · wir sprechen internet 21 Serializer

Slide 22

Slide 22 text

basecom · wir sprechen internet 22 • Abstraktionslayer • Adapter für Symfony Serializer JMS Serializer • Extension-Point für eigene Adapter • Type-Hinting möglich Serializer API

Slide 23

Slide 23 text

basecom · wir sprechen internet 23 Serializer API namespace FOS\RestBundle\Serializer; use FOS\RestBundle\Context\Context; interface Serializer { /** * @param mixed $data * @param string $format * @param Context $context * * @return string */ public function serialize($data, $format, Context $context); // ... }

Slide 24

Slide 24 text

basecom · wir sprechen internet 24 Serializer API namespace FOS\RestBundle\Serializer; use FOS\RestBundle\Context\Context; interface Serializer { // ... /** * @param string $data * @param string $type * @param string $format * @param Context $context * * @return mixed */ public function deserialize($data, $type, $format, Context $context); }

Slide 25

Slide 25 text

basecom · wir sprechen internet 25 View-Instanz erzeugen

Slide 26

Slide 26 text

basecom · wir sprechen internet 26 1.7: FOSRestController namespace AppBundle\Controller; use FOS\RestBundle\Controller\FOSRestController; use Symfony\Component\HttpFoundation\Response; class PostController extends FOSRestController { public function getPostAction($id) { if (null === $post = $this->findPost($id)) { $view = $this->view(null, Response::HTTP_NOT_FOUND); } else { $view = $this->view($post); } return $this->handleView($view); } }

Slide 27

Slide 27 text

basecom · wir sprechen internet 27 1.7: manuell namespace AppBundle\Controller; use FOS\RestBundle\View\View; use Symfony\Component\HttpFoundation\Response; class PostController { // ... public function getPostAction($id) { if (null === $post = $this->findPost($id)) { $view = View::create(null, Response::HTTP_NOT_FOUND); } else { $view = View::create($post); } return $this->viewHandler->handle($view); } }

Slide 28

Slide 28 text

basecom · wir sprechen internet 28 2.0: Trait namespace AppBundle\Controller; use FOS\RestBundle\Controller\ControllerTrait; use Symfony\Component\HttpFoundation\Response; class PostController { use ControllerTrait; public function getPostAction($id) { if (null === $post = $this->findPost($id)) { $view = $this->view(null, Response::HTTP_NOT_FOUND); } else { $view = $this->view($post); } return $this->handleView($view); } }

Slide 29

Slide 29 text

basecom · wir sprechen internet 29 API-Versionierung

Slide 30

Slide 30 text

basecom · wir sprechen internet 30 1.7: URI namespace AppBundle\Controller\Api\V1; use FOS\RestBundle\Controller\Annotations\NamePrefix; /** * @NamePrefix("api_article_v1_") */ class ArticleController { // ... }

Slide 31

Slide 31 text

basecom · wir sprechen internet 31 1.7: URI namespace AppBundle\Controller\Api\V2; use FOS\RestBundle\Controller\Annotations\NamePrefix; /** * @NamePrefix("api_article_v2_") */ class ArticleController { // ... }

Slide 32

Slide 32 text

basecom · wir sprechen internet 32 1.7: URI api_article_v1: resource: AppBundle\Controller\Api\V1\ArticleController type: rest prefix: /v1 api_article_v2: resource: AppBundle\Controller\Api\V2\ArticleController type: rest prefix: /v2

Slide 33

Slide 33 text

basecom · wir sprechen internet 33 1.7: URI $ php app/console debug:router ------------------------------- -------- -------- ------ ----------------------------- Name Method Scheme Host Path ------------------------------- -------- -------- ------ ----------------------------- api_article_v1_get_articles GET ANY ANY /v1/articles.{_format} api_article_v1_get_article GET ANY ANY /v1/articles/{id}.{_format} api_article_v1_post_article POST ANY ANY /v1/articles.{_format} api_article_v1_put_article PUT ANY ANY /v1/articles/{id}.{_format} api_article_v1_delete_article DELETE ANY ANY /v1/articles/{id}.{_format} api_article_v2_get_articles GET ANY ANY /v2/articles.{_format} api_article_v2_get_article GET ANY ANY /v2/articles/{id}.{_format} api_article_v2_post_article POST ANY ANY /v2/articles.{_format} api_article_v2_put_article PUT ANY ANY /v2/articles/{id}.{_format} api_article_v2_delete_article DELETE ANY ANY /v2/articles/{id}.{_format} ------------------------------- -------- -------- ------ -----------------------------

Slide 34

Slide 34 text

basecom · wir sprechen internet 34 2.0: Query-Parameter fos_rest: versioning: enabled: true resolvers: query: enabled: true parameter_name: version GET /articles?version=v2

Slide 35

Slide 35 text

basecom · wir sprechen internet 35 2.0: Mime-Type GET /articles Accept: application/json;version=v1 fos_rest: versioning: enabled: true resolvers: media_type: enabled: true regex: '/(v|version)=(?P[0-9\.]+)/' view: mime_types: json: ['application/json', 'application/json;version=v1', 'application/json;version=v2']

Slide 36

Slide 36 text

basecom · wir sprechen internet 36 2.0: Custom-Header fos_rest: versioning: enabled: true resolvers: custom_header: enabled: true header_name: X-Version GET /articles Accept: application/json X-Version: version=v1

Slide 37

Slide 37 text

basecom · wir sprechen internet 37 Version als Attribut im Request

Slide 38

Slide 38 text

basecom · wir sprechen internet 38 Beispiel: Versionsabhängige Routen api_article_v1: resource: AppBundle\Controller\Api\V1\ArticleController type: rest condition: "request.attributes.get('version') == 'v1'" api_article_v2: resource: AppBundle\Controller\Api\V2\ArticleController type: rest condition: "request.attributes.get('version') == 'v2'"

Slide 39

Slide 39 text

basecom · wir sprechen internet 39 Beispiel: Versionsabhängige Routen namespace AppBundle\Controller\Api\V1; use FOS\RestBundle\Controller\Annotations\Version; /** * @Version("v1") */ class ArticleController { // ... }

Slide 40

Slide 40 text

basecom · wir sprechen internet 40 Versionsabhängige Controller namespace AppBundle\Controller; use Symfony\Component\HttpFoundation\Request; class ArticleController { public function getArticlesAction(Request $request) { if ($request->attributes->get('version', 'v1') === 'v2') { // v2-spezifischer Code } // ... } }

Slide 41

Slide 41 text

basecom · wir sprechen internet 41 REST-Zonen

Slide 42

Slide 42 text

basecom · wir sprechen internet 42 • FOSRest-Listener immer aktiv • verbrauchen Ressourcen • evtl. Konflikt mit anderen Listenern REST-Zonen

Slide 43

Slide 43 text

basecom · wir sprechen internet 43 • Trennung von API und „normaler“ Anwendung • Definition von „REST-Zonen“ anhand von Request-Attributen URI-Pfad Host HTTP-Methode IP-Adressen REST-Zonen

Slide 44

Slide 44 text

basecom · wir sprechen internet 44 REST-Zonen: URI-Pfade fos_rest: zone: - path: '^/api'

Slide 45

Slide 45 text

basecom · wir sprechen internet 45 REST-Zonen: Client-IP-Adresse fos_rest: zone: - ips: ['127.0.0.1']

Slide 46

Slide 46 text

basecom · wir sprechen internet 46 REST-Zonen: Host fos_rest: zone: - host: 'api.example.com'

Slide 47

Slide 47 text

basecom · wir sprechen internet 47 Upgrade

Slide 48

Slide 48 text

basecom · wir sprechen internet 48 • 2.0 nicht vollständig abwärtskompatibel • Vorbild: Symfony 2.8/3.0 • 1.8 Release zeitgleich mit 2.0 • abwärtskompatible Features in 1.8 • Deprecations für BC-Breaks Upgrade-Pfad

Slide 49

Slide 49 text

basecom · wir sprechen internet 49 Vielen Dank! https://joind.in/talk/efed7