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

FOSRest 2.0, SymfonyLive Cologne

FOSRest 2.0, SymfonyLive Cologne

SymfonyLive Cologne, 29. April 2016

Christian Flothmann

April 29, 2016
Tweet

More Decks by Christian Flothmann

Other Decks in Programming

Transcript

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

    2016
  2. basecom · wir sprechen internet 2 Christian Flothmann Software-Entwickler bei

    basecom in Osnabrück - Symfony Core Team - Symfony Documentation Team - Co-Maintainer FOSRestBundle @xabbuh
  3. basecom · wir sprechen internet 3 Was ist das FOSRestBundle?

  4. basecom · wir sprechen internet 4 • Routengenerierung • Dekodierung

    von Requestdaten (JSON, XML, etc.) • Content-Negotiation • Serialisierung von Daten für HTTP-Response Tools für
  5. basecom · wir sprechen internet 5 Warum 2.0?

  6. basecom · wir sprechen internet 6 • gewachsene Codebasis •

    existierende Extension-Points • PHP 5.3 • Symfony 2.3 • aufwändig neue Features zu implementieren
  7. basecom · wir sprechen internet 7 Was gibt es Neues?

  8. 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
  9. basecom · wir sprechen internet 9 HTTP-Methoden nach RFC-2518

  10. basecom · wir sprechen internet 10 • COPY • LOCK

    • MKCOL • MOVE • PROPFIND • PROPPATCH • UNLOCK HTTP-Methoden nach RFC-2518
  11. basecom · wir sprechen internet 11 FOSRestBundle 1.7 namespace AppBundle\Controller;

    class UserController { public function lockUserAction($id) { } }
  12. 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<id>[^/]++)/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 | +--------------+------------------------------------------------------------------+
  13. 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) { } }
  14. 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<id>[^/]++)/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 | +--------------+------------------------------------------------------------------+
  15. basecom · wir sprechen internet 15 FOSRestBundle 2.0 namespace AppBundle\Controller;

    class UserController { public function lockUserAction($id) { } }
  16. 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<id>[^/\.]++)(?:\.(?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 | +--------------+---------------------------------------------------------------+
  17. basecom · wir sprechen internet 17 DirectoryRouteLoader

  18. 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 # ...
  19. basecom · wir sprechen internet 19 FOSRestBundle 2.0 api: resource:

    '@AppBundle/Controller' type: rest
  20. basecom · wir sprechen internet 20 Vorsicht bei sich überlappenden

    Routen!
  21. basecom · wir sprechen internet 21 Serializer

  22. 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
  23. 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); // ... }
  24. 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); }
  25. basecom · wir sprechen internet 25 View-Instanz erzeugen

  26. 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); } }
  27. 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); } }
  28. 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); } }
  29. basecom · wir sprechen internet 29 API-Versionierung

  30. 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 { // ... }
  31. 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 { // ... }
  32. 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
  33. 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} ------------------------------- -------- -------- ------ -----------------------------
  34. 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
  35. 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<version>[0-9\.]+)/' view: mime_types: json: ['application/json', 'application/json;version=v1', 'application/json;version=v2']
  36. 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
  37. basecom · wir sprechen internet 37 Version als Attribut im

    Request
  38. 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'"
  39. basecom · wir sprechen internet 39 Beispiel: Versionsabhängige Routen namespace

    AppBundle\Controller\Api\V1; use FOS\RestBundle\Controller\Annotations\Version; /** * @Version("v1") */ class ArticleController { // ... }
  40. 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 } // ... } }
  41. basecom · wir sprechen internet 41 REST-Zonen

  42. basecom · wir sprechen internet 42 • FOSRest-Listener immer aktiv

    • verbrauchen Ressourcen • evtl. Konflikt mit anderen Listenern REST-Zonen
  43. 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
  44. basecom · wir sprechen internet 44 REST-Zonen: URI-Pfade fos_rest: zone:

    - path: '^/api'
  45. basecom · wir sprechen internet 45 REST-Zonen: Client-IP-Adresse fos_rest: zone:

    - ips: ['127.0.0.1']
  46. basecom · wir sprechen internet 46 REST-Zonen: Host fos_rest: zone:

    - host: 'api.example.com'
  47. basecom · wir sprechen internet 47 Upgrade

  48. 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
  49. basecom · wir sprechen internet 49 Vielen Dank! https://joind.in/talk/efed7