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

REST dans le monde Symfony (PHPTour)

REST dans le monde Symfony (PHPTour)

Voici un tour d'horizon des outils disponibles pour créer des APIs REST robustes en PHP et plus précisément avec le framework Symfony2. Les différentes couches en jeu seront passées en revue, que ce soit le routing, la sérialisation, le versioning, les tests, mais également la documentation de vos APIs. Globalement, cette présentation fera l'état des lieux de REST dans le monde Symfony.

Online slides: http://friendsofsymfony.github.io/slides/rest-dans-le-monde-symfony.html
Sources: https://github.com/FriendsOfSymfony/friendsofsymfony.github.com

William Durand

June 23, 2014
Tweet

More Decks by William Durand

Other Decks in Programming

Transcript

  1. REST  dans  le
    monde  Symfony
    William  Durand  -­‐‑  June  23rd,  2014

    View Slide

  2. Introduction  to  REST

    View Slide

  3. REpresentational  State  Transfer
    REST  is  the  underlying  architectural  principle  of  the  web.
    It  is  formalized  as  a  set  of  constraints,  described  in  Roy
    Fielding'ʹs  dissertation.

    View Slide

  4. Richardson  Maturity  Model
    http://martinfowler.com/articles/richardsonMaturityModel.html

    View Slide

  5. Level  0  -­‐‑  The  Swamp  of  POX
    HTTP  as  a  tunneling  mechanism
    RPC  style  system  (SOAP,  XML-­‐‑RPC)

    View Slide

  6. Level  1  -­‐‑  Resources
    Individual  resources  (URIs)
    Notion  of  object  identity

    View Slide

  7. Level  2  -­‐‑  HTTP  Verbs
    Client
     uses  specific  HTTP  
    verbs
    Server
     uses  HTTP  
    status  codes

    View Slide

  8. HTTP  Verbs
    Method Safe? Idempotent?
    GET yes yes
    HEAD yes yes
    POST no no
    PUT no yes
    DELETE no yes  (*)
    ... no no
    Safe
    :  means  cacheable.
    Idempotent
    :  result  independent
    on  the  number  of  executions.

    View Slide

  9. HTTP  Status  Codes
    Code  range Description Example
    1xx Information 100  -­‐‑  Continue
    2xx Successful 201  -­‐‑  Created
    3xx Redirection 301  -­‐‑  Moved  Permanently
    4xx Client  Error 404  -­‐‑  Not  Found
    5xx Server  Error 501  -­‐‑  Not  Implemented

    View Slide

  10. Level  3  -­‐‑  Hypermedia  Controls
    Service  discovery  via  link  relations
    Hypermedia  formats  (ATOM,  HAL,  JSON-­‐‑LD,  etc.)

    View Slide

  11. Level  3
    =
    Content  Type  Negotiation
    +
    HATEOAS

    View Slide

  12. Content  Type  Negotiation
    Content  Type  Negotiation  is  the  principle  of  finding
    appropriate  response  formats  based  on  client  requirements.
    No  standardized  algorithm  available
    Apache    algorithm  is  documented  though
    Also  covers  encoding  (Accept-Encoding)  and  language
    (Accept-Language)  negotiation
    mod_negotiation

    View Slide

  13. Example
    Accept: application/json, application/xml;q=0.9, text/html;q=0.8,
    text/*;q=0.7, */*;q=0.5
    Priority Description
    q=1.0 application/json
    q=0.9 application/xml
    q=0.8 text/html
    q=0.7 text/*  (ie.  any  text)
    q=0.5 */*  (ie.  any  media  type)

    View Slide

  14. HATEOAS
    Hypermedia  As  The  Engine  Of  Application  State.
    It  means  that  hypermedia  should  be  used  to  find  your  
    way  through  the  API.  It  is  all  about  state  transitions.
    Your  application  is  just  a  big  state  machine.








    View Slide

  15. So  much  for  the  REST  theory  ...

    View Slide

  16. Let'ʹs  Meet  the  Symfony  World!

    View Slide

  17. JMSSerializerBundle

    View Slide

  18. In  A  Nutshell
    Integrates  the    library  with  Symfony2
    Enables  (de)
    serialization  of  object  graphs
    Implements  visitor  pattern  to  enable  flexibility
    Fully  leverage  native  JSON  and  XML
    Custom  
    exclusion  strategies
     to  determine  what  to  serialize
    JMS  Serializer

    View Slide

  19. Usage
    use JMS\SerializerBundle\Annotation as Serializer;
    /** @Serializer\XmlRoot("response") */
    class MyResponse
    {
    /** * @Serializer\XmlList(inline=true, entry="article") */
    protected $articles;
    /** * @Serializer\XmlAttribute() */
    protected $page;
    public function __construct(Collection $articles, $page)
    {
    $this->articles = $articles;
    $this->page = $page;
    }
    }

    View Slide

  20. JSON
    {
    "articles": [
    "bim",
    "bam",
    "bingo"
    ],
    "page": "2"
    }

    View Slide

  21. XML

    bim
    bam
    bingo

    View Slide

  22. FOSRestBundle

    View Slide

  23. In  A  Nutshell
    Toolbox  of  services  and  listeners  to  build  RESTful  APIs
    Generate  HTML,  XML,  JSON  from  a  single  action
    Automatic  generation  of  routes  from  actions
    GET  parameter  parsing  and  validation
    Integration  with  Symfony2  serializer  and  JMS  Serializer
    Integration  with  SensioFrameworkExtraBundle
    Accept  header  negotiation  (thx  to  the    lib)
    Request  body  decoding
    Negotiation

    View Slide

  24. Usage
    class RestController
    {
    /**
    * Get the list of articles
    * route name: liip_hello_rest_get_articles
    * pattern: /liip/hello/rest/articles.{_format}
    * http method requirement: GET
    *
    * @View()
    * @QueryParam(name="page", requirements="\d+", default="1")
    */
    public function getArticlesAction($page)
    {
    $articles = array('bim', 'bam', 'bingo');
    return new \Acme\MyBundle\MyResponse($articles, $page);
    }
    }

    View Slide

  25. HTML



    bim
    bam
    bingo

    page: 2


    View Slide

  26. Content  Type  Negotiation
    fos_rest:
    format_listener:
    rules:
    -
    path: ^/
    priorities: [ html, json, xml ]
    fallback_format: ~
    prefer_extension: true
    Accept: application/json, application/xml;q=0.9, text/html;q=0.8,
    text/*;q=0.7, */*;q=0.5

    View Slide

  27. Message  Decoding
    Listener  to  decode  message  body  from  XML,  JSON,  etc.  into
    the  request  parameter  bag
    Integration  with  SensioFrameworkExtraBundle  converters  to
    turn  parameters  to  objects
    GET  parameter  validation  and  normalization

    View Slide

  28. Allowed  Methods  Listener
    Examines  all  available  routes  to  determine  what  HTTP
    methods  are  available  for  the  request  URI
    Automatically  sets  an  according  Allow  header  in  the
    response
    fos_rest:
    allowed_methods_listener: true
    HTTP/1.1 200 OK
    Allow: GET, POST

    View Slide

  29. MIME  Type  Listener
    Register  MIME  types  that  Symfony2'ʹs  Request  class  does  not
    support  by  default
    fos_rest:
    view:
    mime_types:
    json: ['application/json', 'application/vnd.example-com.foo+json']
    rss: 'application/rss+xml'
    jpg: 'image/jpeg'
    png: 'image/png'
    jsonp_handler: ~
    p  JSONP  callback  validation  thanks  to  the  
     library
    JsonpCallbackValidator

    View Slide

  30. Error  Handling
    Return  correct  HTTP  status  code
    Determine  for  which  exception  to  expose  the  exception
    message
    Automatically  extract  errors  from  a  Form  instance
    fos_rest:
    exception:
    codes:
    'Symfony\Component\Routing\Exception\ResourceNotFoundException': 404
    'Doctrine\ORM\OptimisticLockException': HTTP_CONFLICT
    messages:
    'Symfony\Component\Routing\Exception\ResourceNotFoundException': true

    View Slide

  31. BazingaHateoasBundle

    View Slide

  32. In  A  Nutshell
    Integrates  the    library  with  Symfony2
    Leverages  the  JMS  Serializer  library
    Relies  on  the  Symfony2  ExpressionLanguage  component
    Supports  JSON  and  XML
    Allows  to  configure  links  and  embedded  resources  in
    XML,  YAML,  PHP,  or  Annotations
    Dynamic  relations  (relation  providers)
    Exclusion  strategies
    Hateoas

    View Slide

  33. Usage
    use JMS\Serializer\Annotation as Serializer;
    use Hateoas\Configuration\Annotation as Hateoas;
    /**
    * @Serializer\XmlRoot("user")
    *
    * @Hateoas\Relation("self", href = "expr('/api/users/' ~ object.getId())")
    */
    class User
    {
    /** @Serializer\XmlAttribute */
    private $id;
    private $firstName;
    private $lastName;
    public function getId() {}
    }

    View Slide

  34. JSON
    $hateoas = HateoasBuilder::create()->build();
    $json = $hateoas->serialize(new User(123, 'John', 'Doe'), 'json');
    {
    "id": 123,
    "first_name": "John",
    "last_name": "Doe",
    "_links": {
    "self": {
    "href": "/api/users/123"
    }
    }
    }

    View Slide

  35. XML
    $hateoas = HateoasBuilder::create()->build();
    $xml = $hateoas->serialize(new User(123, 'John', 'Doe'), 'xml');







    View Slide

  36. TemplatedUriBundle

    View Slide

  37. RFC  6570:  URI  Template
    A  compact  sequence  of  characters  for  describing
    a  range  of  URIs  through  variable  expansion.
    URIs URI  Template
    http://example.com/~fred/ http://example.com/~
    {username}/
    http://example.com/~mark/

    View Slide

  38. Usage
    demo_route:
    pattern: /demo/{page}
    $templateLink = $this
    ->get('hautelook.router.template')
    ->generate('demo_route', array(
    'page' => '{page}',
    'sort' => '{sort}',
    'filter' => array('{filter}'),
    ));
    /demo/{page}?{&sort}{&filter%5B%5D*}
    p  Standalone  library:  TemplatedUriRouter

    View Slide

  39. NelmioApiDocBundle

    View Slide

  40. In  A  Nutshell
    Generates  documentation  for  your  REST  APIs
    Gathers  information  from  PHPDoc
    Supports  FOSRestBundle,  SensioFrameworkExtraBundle,
    JMSSerializerBundle  and  JMSSecurityExtraBundle
    annotations
    Supports  your  own  annotations
    Allows  to  add  your  own  parsers
    Sandbox  (Killer  Feature  ♥)

    View Slide

  41. Usage
    /**
    * List all notes.
    *
    * @ApiDoc(
    * resource = true,
    * statusCodes = { 200 = "Returned when successful" }
    * )
    * @QueryParam(
    * name="offset", requirements="\d+", nullable=true,
    * description="Offset from which to start listing notes."
    * )
    * @QueryParam(
    * name="limit", requirements="\d+", default="5",
    * description="How many notes to return."
    * )
    */
    public function getNotesAction() {}

    View Slide

  42. View Slide

  43. LiipCacheControlBundle

    View Slide

  44. In  A  Nutshell
    Response  listener  to  add  Cache-Control  headers
    Listener  matches  the  Request  path/host/method/attributes
    Varnish  helper  class  to  assist  in  purging/banning  content
    Listener  to  combine  reverse  proxies  with  Symfony2  security
    Listener  to  move  flash  messages  into  a  cookie

    View Slide

  45. New  Shiny  Bundle!
    FriendsOfSymfony/FOSHttpCacheBundle

    View Slide

  46. OAuth

    View Slide

  47. What  Is  OAuth?
    OAuth  is  an  open  protocol  to  allow  secure  authorization
    in  a  simple  and  standard  method  from  web,  mobile
    and  desktop  applications.
    It  is  an  authorization  framework  that  enables  a  third-­‐‑party
    application  to  obtain  limited  access  to  an  HTTP  service.
    http://edu.williamdurand.fr/security-­‐‑slides/#slide85

    View Slide

  48. HWIOAuthBundle
    Client-­‐‑side  implementation
    Support  20+  different  providers
    Supports  both  OAuth1.0a  and  OAuth2

    View Slide

  49. FOSOAuthServerBundle
    Server-­‐‑side  implementation  of  OAuth2
    Supports  Doctrine  ORM|ODM,  Propel
    Highly  configurable
    Thank  you    for  helping  us!
    Alan  Gabriel  Bem
     for  OAuth1.0a.
    BazingaOAuthServerBundle

    View Slide

  50. Demo?

    View Slide

  51. gimler/symfony-­‐‑rest-­‐‑edition

    View Slide

  52. willdurand/Propilex

    View Slide

  53. Thank  You.
    Questions?
    ç
    ½
    ­
    «
    joind.in/11215
    williamdurand.fr
    github.com/willdurand
    twitter.com/couac

    View Slide

  54. https://knpuniversity.com/screencast/rest

    View Slide

  55. Further  Reading
    http://www.ietf.org/rfc/rfc2616.txt
    http://martinfowler.com/articles/richardsonMaturityModel.html
    http://roy.gbiv.com/untangled/2008/rest-­‐‑apis-­‐‑must-­‐‑be-­‐‑hypertext-­‐‑driven
    http://www.slideshare.net/Wombert/designing-­‐‑http-­‐‑interfaces-­‐‑and-­‐‑restful-­‐‑web-­‐‑services-­‐‑dpc2012-­‐‑20120608
    http://williamdurand.fr/2012/08/02/rest-­‐‑apis-­‐‑with-­‐‑symfony2-­‐‑the-­‐‑right-­‐‑way/
    http://www.mnot.net/blog/2012/12/04/api-­‐‑evolution
    http://knpuniversity.com/blog/what-­‐‑the-­‐‑rest
    http://knpuniversity.com/blog/rest-­‐‑revisited
    http://timelessrepo.com/haters-­‐‑gonna-­‐‑hateoas
    http://blog.liip.ch/archive/2013/10/28/resting-­‐‑with-­‐‑symfony2.html
    http://williamdurand.fr/2014/02/14/please-­‐‑do-­‐‑not-­‐‑patch-­‐‑like-­‐‑an-­‐‑idiot/

    View Slide