Transcript
Page 1: Give me some REST - RESTful APIs mit Symfony

GIVE ME SOME REST!RESTFUL APIS MIT SYMFONYVon / Paul Seiffert @seiffertp

Page 2: Give me some REST - RESTful APIs mit Symfony

// PAUL SEIFFERTSoftwarearchitekt bei SensioLabs Deutschland GmbH

Page 3: Give me some REST - RESTful APIs mit Symfony

REST?

Page 4: Give me some REST - RESTful APIs mit Symfony

REST!Ressourcen ~ Objekte

HTTP Verben ~ Methoden

Links ~ Assoziationen

Repräsentationen ~ Views

Page 5: Give me some REST - RESTful APIs mit Symfony

ADDRESSIERBARKEITJede Ressource hat eine Adresse (URI)

Beispiel:http://example.com/movies/3

Page 6: Give me some REST - RESTful APIs mit Symfony

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

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

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

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

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

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

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

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

REST UND SYMFONY?Symfony spricht HTTP (und somit auch REST) fließend!

Page 15: Give me some REST - RESTful APIs mit Symfony

ISN'T THERE A BUNDLE FOR REST??

Page 16: Give me some REST - RESTful APIs mit Symfony

ist super!

... für manche Projekte

FOSRestBundle

Page 17: Give me some REST - RESTful APIs mit Symfony

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

MUT ZUR EINFACHEN, SAUBEREN LÖSUNG!

Page 19: Give me some REST - RESTful APIs mit Symfony

Request

Application

Content Negotiation

Routing

Content Retrieval / Update

SerializationResponse

Security

Page 20: Give me some REST - RESTful APIs mit Symfony

SECURITY

Notwendiger Weise stateless

Im einfachsten Fall HTTP Basic Authentication

Page 21: Give me some REST - RESTful APIs mit Symfony

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

ROUTING

/moviesZeigt auf die Liste der Filme

/movies/1Zeigt auf einen bestimmten Film

Page 23: Give me some REST - RESTful APIs mit Symfony

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

SERIALISIERUNG

Die Content-Negotiation bestimmt das Format

Das Routing bestimmt die Daten

Page 25: Give me some REST - RESTful APIs mit Symfony

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

Request

Application

Content Negotiation

Routing

Content Retrieval / Update

SerializationResponse

Security

Page 27: Give me some REST - RESTful APIs mit Symfony

UND JETZT MIT SYMFONY!

Page 28: Give me some REST - RESTful APIs mit Symfony

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

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

NOCH MEHR SECURITY…

https://github.com/FriendsOfSymfony/FOSOAuthServerBundle

Page 31: Give me some REST - RESTful APIs mit Symfony

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

... 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

FÜR SPRACHE UND CHARSET ANALOG.

Page 34: Give me some REST - RESTful APIs mit Symfony

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

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

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

VOM CONTROLLER ZUM MODELL

Controller Service

Domain Model

DTO Mapper

Validator

Page 38: Give me some REST - RESTful APIs mit Symfony

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

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

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

FRAGEN?

Page 42: Give me some REST - RESTful APIs mit Symfony

DANKE!

Page 43: Give me some REST - RESTful APIs mit Symfony

LITERATUR

Martin Fowler -

Richardson Maturity Model

Roy Fielding's Dissertation"Architectural Styles and the Design of Network-basedSoftware Architectures"

Patterns of Enterprise ApplicationArchitecture


Top Related