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

FOSRestBundle, Symfony User Group Cologne

FOSRestBundle, Symfony User Group Cologne

Avatar for Christian Flothmann

Christian Flothmann

March 09, 2016
Tweet

More Decks by Christian Flothmann

Other Decks in Programming

Transcript

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

    basecom in Osnabrück - Symfony Core Team - Symfony Documentation Team - Co-Maintainer FOSRestBundle @xabbuh
  2. basecom · wir sprechen internet 4 1. Client-Server 2. Stateless

    3. Caching 4. Einheitliche Schnittstelle 5. Mehrschichtige Systeme 6. Code on Demand Roy Thomas Fielding (2000)
  3. basecom · wir sprechen internet 9 • Verschiedene URIs •

    Mehrere HTTP-Methoden • Basiert auf HATEOAS (Hypermedia as the Engine of Application State) Level 3
  4. basecom · wir sprechen internet 10 • Routing: diverse HTTP-Methoden,

    viele Controller • Anfragen: kodierter Content (JSON, XML, etc.) • Content-Negotiation • Unterschiedliche Antwortformate je Client Herausforderungen
  5. basecom · wir sprechen internet 12 class PostController { public

    function getPostsAction() { } public function getPostAction($id) { } public function postPostAction() { } public function putPostAction($id) { } public function deletePostAction($id) { } } Routing
  6. basecom · wir sprechen internet 13 # app/config/routing.yml post_api: resource:

    "@AppBundle/Controller/PostController.php" type: rest Routing
  7. basecom · wir sprechen internet 14 $ php app/console debug:router

    ------------- -------- -------- ------ ----------------------- Name Method Scheme Host Path ------------- -------- -------- ------ ----------------------- get_posts GET ANY ANY /posts.{_format} get_post GET ANY ANY /posts/{id}.{_format} post_post POST ANY ANY /posts.{_format} put_post PUT ANY ANY /posts/{id}.{_format} delete_post DELETE ANY ANY /posts/{id}.{_format} ------------- -------- -------- ------ ----------------------- Routing
  8. basecom · wir sprechen internet 16 class PostController { //

    ... public function postPostCommentAction($postId) { } public function getPostCommentsAction($postId) { } public function getPostCommentAction($postId, $commentId) { } } Routing mit Subressourcen
  9. basecom · wir sprechen internet 17 $ php app/console debug:router

    ------------------- -------- -------- ------ ------------------------------------------------ Name Method Scheme Host Path ------------------- -------- -------- ------ ------------------------------------------------ get_posts GET ANY ANY /posts.{_format} get_post GET ANY ANY /posts/{id}.{_format} post_post POST ANY ANY /posts.{_format} put_post PUT ANY ANY /posts/{id}.{_format} delete_post DELETE ANY ANY /posts/{id}.{_format} post_post_comment POST ANY ANY /posts/{postId}/comments.{_format} get_post_comments GET ANY ANY /posts/{postId}/comments.{_format} get_post_comment GET ANY ANY /posts/{postId}/comments/{commentId}.{_format} ------------------- -------- -------- ------ ------------------------------------------------ Routing mit Subressourcen
  10. basecom · wir sprechen internet 18 • Annotationen für: •

    HTTP-Methoden •Path-Prefix •Query- und Request-Parameter •View-Konfiguration •Erlaubte Request-FormatePath-Prefix • Subressourcen in eigener Controller-Klasse Routing – Fine-Tuning
  11. basecom · wir sprechen internet 19 1. Body Listener 2.

    Format Listener 3. View Response Listener Listener
  12. basecom · wir sprechen internet 21 • Body der Anfragen

    mit unterschiedlichem Content Type •JSON •XML •etc. • Problem: Request nicht application/x-www-form-urlencode kodiert • Body Listener: Request Body dekodieren • optional: Array normalisieren • Request ParameterBag aktualisieren Listener – 1. Body Listener
  13. basecom · wir sprechen internet 22 Listener – 1. Body

    Listener # app/config/config.yml fos_rest: body_listener: throw_exception_on_unsupported_content_type: false decoders: json: fos_rest.decoder.json xml: fos_rest.decoder.xml array_normalizer: fos_rest.normalizer.camel_keys
  14. basecom · wir sprechen internet 24 • Aufgabe: Content-Type der

    Antwort bestimmen • Basierend auf Accept-Header des Clients • Prioritäten konfigurierbar Listener – 2. Format Listener
  15. basecom · wir sprechen internet 25 Listeners – 2. Format

    Listener # app/config/config.yml fos_rest: format_listener: enabled: true rules: - path: '^/' host: 'api.%domain%' priorities: ['json', 'xml'] fallback_format: json prefer_extension: false - path: '^/api' priorities: [ 'xml', 'json'] fallback_format: xml attributes: { _controller: FOS\RestBundle\Controller\ExceptionController } prefer_extension: false - path: '^/' priorities: [ 'text/html', '*/*'] fallback_format: html prefer_extension: true
  16. basecom · wir sprechen internet 27 • Keine Response in

    Controller • Stattdessen: Format-unabhängiges View-Object • Konvertierung von View zu Response in Event Listener Listeners – 3. View Response Listener
  17. basecom · wir sprechen internet 28 Listeners – 3. View

    Response Listener use FOS\RestBundle\View\View; class PostController { public function getPostAction($id) { $post = $this->findPost($id); if (null === $post) { $view = View::create(null, 404); } else { $view = View::create($post); } return $view; } }
  18. basecom · wir sprechen internet 29 Listeners – 3. View

    Response Listener alternativ: FOSRestController erweitern
  19. basecom · wir sprechen internet 30 Listeners – 3. View

    Response Listener use FOS\RestBundle\Controller\FOSRestController; class PostController extends FOSRestController { public function getPostAction($id) { // find the blog post by id $post = $this->findPost($id); if (null === $post) { $view = $this->view(null, 404); } else { $view = $this->view($post); } return $view; } }
  20. basecom · wir sprechen internet 32 • COPY • LOCK

    • MKCOL • MOVE • PROPFIND • PROPPATCH • UNLOCK HTTP-Methoden nach RFC-2518
  21. basecom · wir sprechen internet 33 Routing aus Verzeichnis #

    app/config/routing.yml post_api: resource: "@AppBundle/Controller/Api/PostController.php" type: rest post_comment_api: resource: "@AppBundle/Controller/Api/PostCommentController.php" type: rest article_api: resource: "@AppBundle/Controller/Api/ArticleController.php" type: rest article_comment_api: resource: "@AppBundle/Controller/Api/ArticleCommentController.php" type: rest tag_api: resource: "@AppBundle/Controller/Api/TagController.php" type: rest
  22. basecom · wir sprechen internet 34 Routing aus Verzeichnis api:

    resource: "@AppBundle/Controller/Api" type: rest
  23. basecom · wir sprechen internet 37 Routing aus Verzeichnis api:

    resource: "%kernel.root_dir%/../src/AppBundle/Controller/Api" type: rest Achtung: Funktioniert leider auch nicht!
  24. basecom · wir sprechen internet 40 • View-Handling ohne Symfony

    Basis-Controller • Shortcut-Methoden zum Handling von Views: view() redirectView()/routeRedirectView() handleView() setViewHandler()/getViewHandler() Controller Trait
  25. basecom · wir sprechen internet 41 Controller Trait use FOS\RestBundle\Controller\FOSRestController;

    class PostController extends FOSRestController { public function getPostAction($id) { // find the blog post by id $post = $this->findPost($id); if (null === $post) { $view = $this->view(null, 404); } else { $view = $this->view($post); } return $view; } }
  26. basecom · wir sprechen internet 42 Controller Trait use FOS\RestBundle\Controller\ControllerTrait;

    class PostController { use ControllerTrait; public function getPostAction($id) { // find the blog post by id $post = $this->findPost($id); if (null === $post) { $view = $this->view(null, 404); } else { $view = $this->view($post); } return $view; } }
  27. basecom · wir sprechen internet 43 • Abstraktionslayer • Adapter

    für Symfony Serializer JMS Serializer • Extension-Point für eigene Adapter • Type-Hinting möglich Serializer-Layer
  28. basecom · wir sprechen internet 44 Serializer-Layer 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); // ... }
  29. basecom · wir sprechen internet 45 Serializer-Layer 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); }
  30. basecom · wir sprechen internet 46 • Unterschiedliche Strategien: URI-Parameter

    (/v1/users) Query-Parameter (/users?version=v1) Mime-Type-Header (Accept: application/json; version=1.0) Eigener Header (X-Accept-Version: v1) • Wahl aktivierter Strategien • Strategien priorisierbar • Aktuelle Version als Attribut des Requests verfügbar Versionierung
  31. basecom · wir sprechen internet 47 Versionierung # app/config/config.yml fos_rest:

    versioning: enabled: true resolvers: query: true custom_header: enabled: true header_name: X-Accept-Version media_type: enabled: true regex: '/(v|version)=(?P<version>[0-9\.]+)/' guessing_order: - query - custom_header - media_type
  32. basecom · wir sprechen internet 48 • FOSRest-Listener bei jedem

    Request aktiv • Verbrauchen Ressourcen • ggfl. Konflikt mit anderen Listenern REST-Zonen
  33. basecom · wir sprechen internet 49 • Trennung von API

    und „normaler“ Anwendung • Definition von „REST-Zonen“ anhand von Request-Attributen URI-Pfad Host HTTP-Methode IP-Adressen REST-Zonen
  34. basecom · wir sprechen internet 50 REST-Zonen # app/config/config.yml fos_rest:

    zone: - path: '^/api' - path: '/test' ips: ['127.0.0.1'] - path: '/api-test' host: 'api-test.example.com'
  35. basecom · wir sprechen internet 55 • 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 • Deprecation-Trigger für BC-Breaks Upgrade-Pfad