Skip to content

Instantly share code, notes, and snippets.

@OlivierParent
Last active December 6, 2017 13:38
Show Gist options
  • Save OlivierParent/4f6fa29d060fb4c251a7 to your computer and use it in GitHub Desktop.
Save OlivierParent/4f6fa29d060fb4c251a7 to your computer and use it in GitHub Desktop.
Symfony - RESTful API.md

NMDAD III — Symfony — RESTful API

New Media Design & Development III - The Symfony Framework Academiejaar 2014-2015, Arteveldehogeschool ©2014 Olivier Parent


[TOC]


I. Introductie

http://www.ibm.com/developerworks/webservices/library/ws-restful/ http://martinfowler.com/articles/richardsonMaturityModel.html http://symfony.com/video/26/designing-http-interfaces-and-restful-web-services/English http://welcometothebundle.com/symfony2-rest-api-the-best-2013-way/

1. REST

REST (Representational State Transfer) is een architecturale stijl voor software die in 2000 door Roy Thomas Fielding beschreven werd in zijn doctoraatsthesis Architectural Styles and the Design of Network-based Software Architectures aan de University of California, Irvine.

1.1 RESTful

De mate waarin de REST architeturale stijl geïmplementeerd wordt, wordt weergegeven op de schaal van het Richardson Maturity Model (RMM) van Leonard Richardson:

  • Niveau 0 — HTTP
  • Niveau 1 — Resources: de complexiteit van de web service wordt opgedeeld in resources.
  • Niveau 2 — HTTP-methoden: zodat de handelingen op de resources op een uniforme manier kunnen gebeuren.
  • Niveau 3 — HATEOAS (Hypermedia as the Engine of Application State): de mogelijkheden van de web service zijn te ontdekken, want de koppelingen (hyperlinks) en relaties (IANA Link Relations) naar mogelijke acties die volgen op de laatste actie zitten in de hypermedia. XML en JSON zijn geen hypermedia, maar er kunnen hypermedia van gemaakt worden, bijv. HTML, XHTML en Atom.

RMM Niveau 3 is RESTful en is vereist om te voldoen aan de REST architecturale stijl, maar is op zich nog altijd niet voldoende om over REST te kunnen spreken. Dus: REST is altijd RESTful, maar RESTful is niet noodzakelijk REST.

Opmerking: Veel API's implementeren RMM Niveau 3 niet, en dat is oké want RESTful kan in veel gevallen overkill zijn. Maar strict gezien is het dan geen RESTful API en al zeker geen REST API!

1.1.1 RESTful Web Service

Bron: http://www.ibm.com/developerworks/webservices/library/ws-restful/

A. Kenmerken

De kenmerken van een RESTful Web Service:

  • Maakt expliciet gebruik van HTTP-methoden (POST, GET, PUT, DELETE …) om acties uit te voeren op Resources
  • Gebruikt HTTP-statuscodes (200, 204, 404 …) om weer te geven of het resultaat succesvol was.
  • Is stateless (de server moet geen state (de opgeslagen infomatie op een bepaald tijdstip) bijhouden die invloed hebben op de response op een request)
  • URI's die een mappenstructuur voorstellen (uniform interface?)
  • Transfer view dus: HTML, XML, XHTML, JSON, e.d.

Opmerking:

Een URI (Uniform Resource Identifier) bestaat uit een URL (Uniform Resource Locator) en/of URN (Uniform Resource Name)

B. Stateless versus Stateful

Stateful is bijvoorbeeld:

http://www.example.com/users

Welke User-resource de URI voorstelt hangt af van wie aangemeld is.

Stateless is bijvoorbeeld:

http://www.example.com/users/123

De URI stelt altijd de User-resource voor die 123 als identifier heeft. De gegevens van User 123 kunnen dan wel veranderen, maar het blijft altijd User 123. Hierdoor kan de server de response cachen.

1.1.2 Goede RESTful URI's

2. REST en Symfony

Symfony heeft out-of-the-box een vrij beperkte ondersteuning voor RESTful API's, maar gelukkig bestaat er een goede Bundle van FOS.

Weetje:

FOS (FriendsOfSymfony) is een intiatief van enkele Symfony2-developers van KNP Labs. FOS heeft enkele van de 30 meest nuttige Symfony Bundles ontwikkeld.

HTTP-methoden

Bron: http://williamdurand.fr/2012/08/02/rest-apis-with-symfony2-the-right-way/

HTTP-methoden worden ook HTTP-werkwoorden (HTTP verbs) genoemd.

HTTP-methode Betekenis CRUD-mapping Idempotent? Veilig? Opmerking
POST Resource aanmaken CREATE Nee Nee
GET Resource opvragen READ Ja Ja message body verplicht
HEAD Resource opvragen READ Ja Ja message body niet verplicht
PATCH Resource wijzigen UPDATE Ja Nee
PUT Resource vervangen UPDATE Ja Nee
DELETE Resource verwijderen DELETE Ja Nee

Opmerkingen:

  • Zie ook: Hypertext Transfer Protocol (HTTP/1.1): Request Methods
  • Veilig: er kunnen geen ongewenste dingen gebeuren (zoals bijvoorbeeld het wijzigen van gegevens).
  • Idempotent: zelfde effect ongeacht hoeveel keer de request herhaald wordt. Daardoor mogelijk om de response te cachen door bijvoorbeeld een reverse proxy proxyserver zoals Varnish Cache.

3. CORS (Cross-Origin Resource Sharing)

3.1 Inleiding

Een moderne User Agent (bijv. browser of app) heeft een Same-Origin Security Policy. Dit wil zeggen dat de bronnen (resources), zoals bijvoorbeeld JavaScript-bestanden of gegevens, allen dezelfde oorsprong (protocol, domein en poort) moeten hebben, zoniet worden ze geweigerd.

Eén manier om deze beperking te omzeilen is werken met JSON-P, maar daar kan je enkel gegevens mee inlezen. Een andere manier is werken met een proxyscript op hetzelfde domein als de User Agent, maar dit is niet altijd mogelijk

De betere manier is CORS inschakelen. CORS is een W3C Recommendation die door moderne User Agents geïmplementeerd is.

3.2 Server-Side

De server moet aangeven dat CORS ingeschakeld is voor het domein dat een request stuurt. Dit kan eenvoudig door een Access-Control-Allow-Origin in de header van de response te zetten met een van deze opties:

  • * voor alle domeinen;
  • een echo van het domein waarvan de request komt (dit komt op hetzelfde neer als de eerste optie);
  • bijv. http://www.example.org voor een welbepaald domein.

Je kan dit doen in PHP met:

// Laat alle domeinen toe.
header('Access-Control-Allow-Origin: *');

Of in de configuratie van de server (in dit geval NGINX):

# Laat alle domeinen toe.
add_header Access-Control-Allow-Origin: '*';

Opgelet: in bovenstaand voorbeeld zijn de aanhalingstekens (') van belang! Indien ze er niet staan zal bij een wijziging van de Access-Control-Allow-Origin (bijv. door PHP), de gewijzigde origin er aan toegevoegd worden waardoor er meerdere waarden staan en User Agents laten maar één waarde toe waardoor het niet langer geldig is!

II. Installatie

Zie ook:

We gaan een aantal Symfony Bundles installeren:

1. Bundles Installeren

$ cd ~/Code/nmdad-iii.arteveldehogeschool.be/www/
$ composer require friendsofsymfony/rest-bundle:@stable jms/serializer-bundle:@stable nelmio/api-doc-bundle:@stable nelmio/cors-bundle:'~1.3'

Daarna moeten we de Bundles registreren in app/AppKernel.php

class AppKernel extends Kernel
{
    public function registerBundles()
    {
        $bundles = array(
        // …
            new FOS\RestBundle\FOSRestBundle(),
            new JMS\SerializerBundle\JMSSerializerBundle(),
            new Nelmio\ApiDocBundle\NelmioApiDocBundle(),
            new Nelmio\CorsBundle\NelmioCorsBundle(),
        // …
        );
    }
}

2. Nelmio API Doc

Voor de NelmioApiDocBundle moeten we nog een route toevoegen aan app/config/routing.yml:

#
NelmioApiDocBundle:
    resource: "@NelmioApiDocBundle/Resources/config/routing.yml"
    prefix:   /api/doc
#

In # app/config/config.yml:

# Nelmio ApiDocBundle
nelmio_api_doc:
    name: "Arteveldehogeschool Blog API documentation"
    sandbox:
        accept_type: application/json

Test met: http://dev.nmdad-iii.arteveldehogeschool.be/api/doc/

3. Nelmio CORS

In # app/config/config.yml:

nelmio_cors:
    paths:
        '^/api/':
            allow_origin: '*'
            allow_headers: ['X-Custom-Auth','Content-Type']
            allow_methods: ['POST', 'PUT', 'GET', 'DELETE', 'OPTIONS']
            max_age: 3600

III. Gebruik

1. Beginvoorwaarden

We bouwen verder op het blogsysteem in Symfony.md

2. FOSRestController Aanmaken

De controllers geven we de naam zoals het meervoud van de Entity Articles. We maken eerst een kopie van src/Artvelde/ApiBundle/Controller/DefaultController.php, die we gaan omvormen tot een FOSRestController:


Je kan ook een lijst van routes opvragen via de Symfony-Console met:

vagrant@homestead$ php app/console api:doc:dump

of

vagrant@homestead$ php app/console router:debug | grep 'artevelde_api'

Tip: Routes testen met Nelmio ApiDoc

Bekijk de routes op http://dev.nmdad-iii.arteveldehogeschool.be/api/doc/ en klik daarna op een route en probeer deze in de Sandbox.

...

Zie ook:

3. Entity Aanpassen

Zie ook:

  • [Johannes Schmitt / Serializer / Reference / Annotations](http://jmsyst.com/libs/serializer/master/reference/annotations)
    
  • [Johannes Schmitt / Serializer / Cookbook / Exclusion Strategies](http://jmsyst.com/libs/serializer/master/cookbook/exclusion_strategies)
    

Omdat niet alle eigenschappen van de Entity geserialiseerd mag worden, moeten met annotations een aantal dingen aanpassen.

Listeners

https://github.com/FriendsOfSymfony/FOSRestBundle/blob/master/Resources/doc/3-listener-support.md#format-listener

Forms

Bij een POST of PUT wordt een request naar de Controller Action gestuurd. Een eenvoudige manier om een Entity op te vullen met de waarde n uit de request is door de entity te koppelen aan een Form-object en de Request-object te binden aan dat Form-object. Zo krijgt de Entity de waarden uit het form-object en kan eveneens de geldigheid van de gegevens gecontroleerd worden via form validatie.

vagrant@homestead$ php app/console generate:doctrine:form ArteveldeCommonBundle:Article 

Verplaats daarna de Form Type klasse naar de ArteveldeApiBundle in een nieuwe map Form\ en vergeet niet de namespace aan te passen met de naam van de nieuwe Bundle.

Testen

PhpStorm

ToolsTest RESTful Web Service

  • HTTP method: POST

  • Host/port: http://dev.nmdad-iii.arteveldehogeschool.be

  • Path: /api/v1/users/1/articles/

  • Request+

    Name Value
    Content-Type application/json
  • Request Body

    Text:

    {
    	"article": {
    		"title": "Test Artikel C",        
    		"body": "Lorem Ipsum C"
    	}
    }
  • Druk op het groene Run-icoontje.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment