give me some rest - restful apis mit symfony
DESCRIPTION
Webservices werden heute in vielen Bereichen der IT zur Integration unterschiedlicher Anwendungen verwendet. Die Klasse der REST-Webservices spielt dabei eine besondere Rolle, da REST sich auf die Grundlagen von HTTP stützt, einfach verständlich ist und relativ einfach in bestehende Anwendungen zu integrieren ist. Dieser Vortrag gibt einen Überblick über die Herausforderungen einer RESTful API und zeigt, wie diese mit der Hilfe von Symfony einfach gelöst werden können. Diese Slides habe ich für meinen Vortrag auf der DWX 2014 genutzt.TRANSCRIPT
![Page 1: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/1.jpg)
GIVE ME SOME REST!RESTFUL APIS MIT SYMFONYVon / Paul Seiffert @seiffertp
![Page 2: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/2.jpg)
// PAUL SEIFFERTSoftwarearchitekt bei SensioLabs Deutschland GmbH
![Page 3: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/3.jpg)
REST?
![Page 4: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/4.jpg)
REST!Ressourcen ~ Objekte
HTTP Verben ~ Methoden
Links ~ Assoziationen
Repräsentationen ~ Views
![Page 5: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/5.jpg)
ADDRESSIERBARKEITJede Ressource hat eine Adresse (URI)
Beispiel:http://example.com/movies/3
![Page 6: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/6.jpg)
UNIFORM INTERFACEMovieCollection
title: StringreleaseDate: Date
Moviecharacter: String
Role
name: stringdateOfBirth: Date
Actor
*
1
1 *
1
*
GET /moviesPOST /moviesGET /movies/1PUT /movies/1DELETE /movies/1
![Page 7: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/7.jpg)
GET /movies
HTTP/1.1 200 OKDate: Mon, 14 Jul 2014 12:10:00 GMT
{ "movies": [ { "title": "Indiana Jones and the Temple of Doom", "uri": "/movies/1" }, { "title": "Indiana Jones and the Last Crusade", "uri": "/movies/2" }, { "title": "Indiana Jones and the Temple of the Forbidden Eye", "uri": "/movies/3" } ]}
![Page 8: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/8.jpg)
POST /movies
POST /movies HTTP/1.1Content-Type: application/json
{ "movie": { "title": "Indiana Jones and the Kingdom of the Crystal Skull", "releaseDate": "22 May 2008" }}
![Page 9: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/9.jpg)
POST /movies
HTTP/1.1 201 CreatedDate: Mon, 14 Jul 2014 12:15:01 GMTLocation: /movies/4
![Page 10: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/10.jpg)
GET /movies/1
HTTP/1.1 200 OKDate: Mon, 14 Jul 2014 12:10:00 GMT
{ "movie": { "title": "Indiana Jones and the Temple of Doom", "releaseDate": "22 May 1984" }, "uri": "/movies/1"}
![Page 11: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/11.jpg)
PUT /movies/1
PUT /movies/1 HTTP/1.1Content-Type: application/json
{ "movie": { "title": "Indiana Jones and the Temple of Doom", "releaseDate": "23 May 1984" }}
![Page 12: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/12.jpg)
PUT /movies/1
HTTP/1.1 204 No ContentDate: Mon, 14 Jul 2014 12:15:01 GMT
![Page 13: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/13.jpg)
DELETE /movies/1
HTTP/1.1 204 No ContentDate: Mon, 14 Jul 2014 12:20:00 GMT
![Page 14: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/14.jpg)
REST UND SYMFONY?Symfony spricht HTTP (und somit auch REST) fließend!
![Page 15: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/15.jpg)
ISN'T THERE A BUNDLE FOR REST??
![Page 17: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/17.jpg)
HERAUSFORDERUNGEN"REST-Syntax"
Abbildung des Domain Models auf Ressourcen
Abbildung der Domain-Logik auf das Uniform Interface
Perfektionistisch sein!
Pragmatisch sein!
![Page 18: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/18.jpg)
MUT ZUR EINFACHEN, SAUBEREN LÖSUNG!
![Page 19: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/19.jpg)
Request
Application
Content Negotiation
Routing
Content Retrieval / Update
SerializationResponse
Security
![Page 20: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/20.jpg)
SECURITY
Notwendiger Weise stateless
Im einfachsten Fall HTTP Basic Authentication
![Page 21: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/21.jpg)
CONTENT-NEGOTIATIONGET / HTTP/1.1Host: google.com
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8Accept-Encoding: gzip,deflate,sdchAccept-Language: en-US,en;q=0.8,de;q=0.6
HTTP/1.1 200 OK
Content-Type: text/htmlContent-Language: enContent-Encoding: gzip
HTTP/1.1 406 Not Acceptable
![Page 22: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/22.jpg)
ROUTING
/moviesZeigt auf die Liste der Filme
/movies/1Zeigt auf einen bestimmten Film
![Page 23: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/23.jpg)
ROUTING
GET /moviesGibt die Liste der Filme zurück
POST /moviesLegt einen neuen Film an
![Page 24: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/24.jpg)
SERIALISIERUNG
Die Content-Negotiation bestimmt das Format
Das Routing bestimmt die Daten
![Page 25: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/25.jpg)
SERIALISIERUNG$result = new MovieResult(new Movie('Star Wars: A New Hope', '25 May 1977'));
$serializedContent = $serializer->serialize($result, 'json');
echo $serializedContend;
{ "movie": { "title": "Star Wars: A New Hope", "releaseDate": "25 May 1977" }}
![Page 26: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/26.jpg)
Request
Application
Content Negotiation
Routing
Content Retrieval / Update
SerializationResponse
Security
![Page 27: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/27.jpg)
UND JETZT MIT SYMFONY!
![Page 28: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/28.jpg)
Request
Application
Content Negotiation
Routing
Content Retrieval / Update
SerializationResponse
RequestListener
View Listener
Symfony Routing
Controller / Domain Logic
Security Symfony Security
![Page 29: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/29.jpg)
SECURITYsecurity: firewalls: api: pattern: ̂/ http_basic: realm: "My Movie REST API" stateless: true
access_control: - { path: ̂/, roles: ROLE_USER }
![Page 30: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/30.jpg)
NOCH MEHR SECURITY…
https://github.com/FriendsOfSymfony/FOSOAuthServerBundle
![Page 31: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/31.jpg)
CONTENT NEGOTIATION
https://github.com/willdurand/Negotiation<?php
$negotiator = new \Negotiation\FormatNegotiator();
$acceptHeader = 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8';$priorities = array('html', 'application/json', '*/*');
$format = $negotiator->getBestFormat($acceptHeader, $priorities);// $format == html
![Page 32: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/32.jpg)
... IN EINEM REQUEST-LISTENER:<?php
class FormatListener{ public function onRequest(GetResponseEvent $event) { $request = $event->getRequest();
$format = $this->negotiator->getBestFormat( $request->headers->get('Accept'), $this->availableFormats ); if (null === $format) { $format = $this->defaultFormat; }
$request->attributes->set('_format', $format); }}
![Page 33: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/33.jpg)
FÜR SPRACHE UND CHARSET ANALOG.
![Page 34: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/34.jpg)
ROUTINGmovies_list: pattern: /movies methods: GET defaults: { _controller: MoviesApiBundle:Movies:get }
movies_add: pattern: /movies methods: POST defaults: { _controller: MoviesApiBundle:Movies:post }
movie_get: pattern: /movies/{id} methods: GET defaults: { _controller: MoviesApiBundle:Movie:get }
movie_put: pattern: /movies/{id} methods: PUT defaults: { _controller: MoviesApiBundle:Movie:put }
movie_delete: pattern: /movies/{id} methods: DELETE defaults: { _controller: MoviesApiBundle:Movie:delete }
![Page 35: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/35.jpg)
DER CONTROLLERÜbersetzt aus HTTP-Logik in Applikations-Logik
Erstellt Responses oder gibt angeforderten Daten zurück
Arbeitet (fast) format-agnostisch
Und bitte mit !DTOs
![Page 36: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/36.jpg)
<?php
class MoviesController{ public function getAction() { return $this->movieApiService->getMovieList(); }
public function postAction(Request $request) { $movie = $this->serializer->deserialize( $request->getContent(), 'MovieDto', $request->attributes->get('_contentType') );
$this->movieApiService->addMovie($movie);
$response = new Response('', 201); $response->headers->set( 'Location', $this->generateUrl('movie_get', ['id' => $movie->getId()]) );
return $response; }}
![Page 37: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/37.jpg)
VOM CONTROLLER ZUM MODELL
Controller Service
Domain Model
DTO Mapper
Validator
![Page 38: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/38.jpg)
SERIALISIERUNG https://github.com/schmittjoh/serializer
<?php
$serializer = $container->get('jms_serializer');
$serializedMovie = $serializer->serialize($movie, 'json');$movie = $serializer->deserialize($serializedMovie, 'MovieDto', 'json');
![Page 39: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/39.jpg)
SERIALIZER MAPPINGMovieDto: exclusion_policy: all properties: title: expose: true type: string releaseDate: expose: true type: Date
![Page 40: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/40.jpg)
<?php
use Symfony\Component\HttpFoundation\Response;use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
class ResponseSerializationListener{ public function onView(GetResponseForControllerResultEvent $event) { $request = $event->getRequest();
$content = $this->serializer->serialize( $event->getControllerResult(), $request->attributes->get('_format') );
$event->setResponse(new Response($content)); }}
![Page 41: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/41.jpg)
FRAGEN?
![Page 42: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/42.jpg)
DANKE!
![Page 43: Give me some REST - RESTful APIs mit Symfony](https://reader034.vdocuments.net/reader034/viewer/2022042700/555e27c0d8b42a384f8b503e/html5/thumbnails/43.jpg)
LITERATUR
Martin Fowler -
Richardson Maturity Model
Roy Fielding's Dissertation"Architectural Styles and the Design of Network-basedSoftware Architectures"
Patterns of Enterprise ApplicationArchitecture