Slide 1

Slide 1 text

basecom · wir sprechen internet 1 FOSRestBundle

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 REST?

Slide 4

Slide 4 text

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)

Slide 5

Slide 5 text

basecom · wir sprechen internet 5 REST Maturity Model nach Leonard Richardson

Slide 6

Slide 6 text

basecom · wir sprechen internet 6 • XML-RPC/SOAP • Eine URI • Eine HTTP-Methode Level 0

Slide 7

Slide 7 text

basecom · wir sprechen internet 7 • Verschiedene URIs • Aber nur eine HTTP-Methode Level 1

Slide 8

Slide 8 text

basecom · wir sprechen internet 8 • Verschiedene URIs • Mehrere HTTP-Methoden Level 2

Slide 9

Slide 9 text

basecom · wir sprechen internet 9 • Verschiedene URIs • Mehrere HTTP-Methoden • Basiert auf HATEOAS (Hypermedia as the Engine of Application State) Level 3

Slide 10

Slide 10 text

basecom · wir sprechen internet 10 • Routing: diverse HTTP-Methoden, viele Controller • Anfragen: kodierter Content (JSON, XML, etc.) • Content-Negotiation • Unterschiedliche Antwortformate je Client Herausforderungen

Slide 11

Slide 11 text

basecom · wir sprechen internet 11 Routing

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

basecom · wir sprechen internet 13 # app/config/routing.yml post_api: resource: "@AppBundle/Controller/PostController.php" type: rest Routing

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

basecom · wir sprechen internet 15 Routing mit Subressourcen

Slide 16

Slide 16 text

basecom · wir sprechen internet 16 class PostController { // ... public function postPostCommentAction($postId) { } public function getPostCommentsAction($postId) { } public function getPostCommentAction($postId, $commentId) { } } Routing mit Subressourcen

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

basecom · wir sprechen internet 19 1. Body Listener 2. Format Listener 3. View Response Listener Listener

Slide 20

Slide 20 text

basecom · wir sprechen internet 20 Listener 1. Body Listener

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

basecom · wir sprechen internet 23 Listener 2. Format Listener

Slide 24

Slide 24 text

basecom · wir sprechen internet 24 • Aufgabe: Content-Type der Antwort bestimmen • Basierend auf Accept-Header des Clients • Prioritäten konfigurierbar Listener – 2. Format Listener

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

basecom · wir sprechen internet 26 Listeners 3. View Response Listener

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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; } }

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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; } }

Slide 31

Slide 31 text

basecom · wir sprechen internet 31 FOSRestBundle 2.0

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

basecom · wir sprechen internet 35 Routing aus Verzeichnis

Slide 36

Slide 36 text

basecom · wir sprechen internet 36 Routing aus Verzeichnis

Slide 37

Slide 37 text

basecom · wir sprechen internet 37 Routing aus Verzeichnis api: resource: "%kernel.root_dir%/../src/AppBundle/Controller/Api" type: rest Achtung: Funktioniert leider auch nicht!

Slide 38

Slide 38 text

basecom · wir sprechen internet 38 Routing aus Verzeichnis

Slide 39

Slide 39 text

basecom · wir sprechen internet 39 Routing aus Verzeichnis

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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; } }

Slide 42

Slide 42 text

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; } }

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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); // ... }

Slide 45

Slide 45 text

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); }

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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[0-9\.]+)/' guessing_order: - query - custom_header - media_type

Slide 48

Slide 48 text

basecom · wir sprechen internet 48 • FOSRest-Listener bei jedem Request aktiv • Verbrauchen Ressourcen • ggfl. Konflikt mit anderen Listenern REST-Zonen

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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'

Slide 51

Slide 51 text

basecom · wir sprechen internet 51 Release?

Slide 52

Slide 52 text

basecom · wir sprechen internet 52

Slide 53

Slide 53 text

basecom · wir sprechen internet 53 { "require": { "friendsofsymfony/rest-bundle": "~2.0@beta" } }

Slide 54

Slide 54 text

basecom · wir sprechen internet 54 Upgraden?

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

basecom · wir sprechen internet 56 Vielen Dank für die Aufmerksamkeit!