Logo Node.js Paris

REST World

REST World

  • Qu'est-ce qu'une API ?
  • Qu'est-ce que REST ?
  • REST de 0 à 5
  • Les Frameworks NodeJS

Qu'est-ce qu'une API ?

API

Application Programming Interface

Interface de Programmation

GET https://api.github.com?callback=foo

GET http://docs.oracle.com/javase/7/docs/api/

GET http://www.viedemerde.fr/

Heu ... DOM

Qu'est-ce que REST ?

  • Un type d'architecture d'API
  • orienté services
  • qui contient plusieurs niveaux de définition

Qu'est-ce qu'une API REST ?

Une API REST expose une collection de ressources et permet d'agir dessus

On dit que REST est :

Client-serveur
on abstrait la persistance
Statelessscalable/extensible, pas de sessions à gérer
Uniformesimple à utiliser
Mutablesimple à entretenir/modifier/adapter
Performantencore mieux avec une gestion du cache intelligente
Portable(avec quelques ajustements, notamment pour l'univers mobile)

REST -> niveau 0


To: <soap@example.org>
From: <soap@client.com>
Reply-To: <soap@client.com>
Date: Tue, 15 Nov 2001 23:27:00 -0700
Message-Id: <1F75D4D515C3EC3F34FEAB51237675B5@client.com>
MIME-Version: 1.0
Content-Type: text/xml; charset=utf-8
Content-Transfer-Encoding: QUOTED-PRINTABLE

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
  xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
  xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<m:echoString xmlns:m="http://soapinterop.org/">
<inputString>get your SOAP over SMTP here !</inputString>
</m:echoString>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

...
          

SOAP via SMTP

REST -> niveau 0

Utilisation du protocole HTTP

Ce niveau est "facultatif" (mais on a pas mieux aujourd'hui)

Utilisation du protocole HTTP

Pourquoi ?

  • Pour pouvoir valider les niveaux suivants ...
  • HTTP propose des méthodes HTTP, des headers HTTP et des codes HTTP bien pratiques
  • HTTP est client-serveur
  • HTTP est uniforme du fait de son universalité sur le web
  • HTTP s'utilise sur de nombreux supports, dont les mobiles
  • HTTP est performant (pour un protocole textuel) ... merci SPDY

POST /schema-instance HTTP/1.1
Host: www.soap.example.org
SOAPAction: "Some-URI"

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
  xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
  xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<m:echoString xmlns:m="http://soapinterop.org/">
<inputString>get your SOAP over HTTP here !</inputString>
</m:echoString>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

...
          

SOAP via HTTP

LEVEL UP !

REST -> niveau 1


POST /schema-instance HTTP/1.1
Host: www.soap.example.org
SOAPAction: "Some-URI"

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
  xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
  xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<m:echoString xmlns:m="http://soapinterop.org/">
<inputString>get your SOAP over HTTP here !</inputString>
</m:echoString>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

...
          

SOAP via HTTP


GET /data/2.0/Equipements/get_equipements HTTP/1.1
Host: api.paris.fr

HTTP/1.1 200 OK

{
  "status": "success",
  "data": [
    {
      "name": "Crèche collective municipale de Cotte",
      "address": "7 rue de Cotte ",
      "zipCode": 75012
    }
  ],
  "api-version": "2.0",
  // ...
}
          

GET /data/2.1/Equipements/get_equipements HTTP/1.1
Host: api.paris.fr

HTTP/1.1 200 OK

{
  "status": "success",
  "data": [
    {
      "name": "Crèche collective municipale de Cotte",
      "address": "7 rue de Cotte ",
      "zipCode": 75012
    }
  ],
  "api-version": "2.1",
  // ...
}
          

1 ressource, 2 URIs


GET /2.0/lists/member.json HTTP/1.1
Host: us2.api.mailchimp.com

HTTP/1.1 200 OK

{
  "apikey": "example apikey",
  "id": "example id",
  "email": {
    "email": "example email",
    "euid": "example euid",
    "leid": "example leid"
  },
  // ...
}
          

GET /2.0/lists/member.xml HTTP/1.1
Host: us2.api.mailchimp.com

HTTP/1.1 200 OK

<xml>
  <apikey>example apikey</apikey>
  <id>example id</id>
  <email>
    <email>example email</email>
    <euid>example euid</euid>
    <leid>example leid</leid>
  </email>
  <!-- ... -->
</xml>
          

1 ressource, 2 URIs

REST -> niveau 1

1 Resource = 1 URI

1 Resource = 1 URI

Pourquoi ?

  • Pour pouvoir utiliser la puissance des URI (Uniform Resource Identifiers)
  • URI c'est uniforme du fait de son universalité
  • 1 URI, donc pas d'état dans l'adresse
  • 1 URI, c'est plus facile à entretenir, tous les chemins vont à Rome

Cool URIs don't change

  • Utilisez des noms, pas des verbes

  • Une liste de clients ? /client
  • Un client particulier ? /client/1

  • OU

  • Une liste de clients ? /clients
  • Un client particulier ? /clients/1
  • Important : la consistance des noms

Cool URIs don't change 2

  • Une liste de clients ?
  • /client : ressource à accéder
  • /client/ : redirection (301)

  • OU

  • l'inverse

Cool URIs don't change 3

  • Pour les noms composés, évitez les Majuscules, préférez les tirets (-)

  • Une liste de clients techniques ?

  • NON : /technicalClient
  • OUI : /technical-client

UPRI

  • Pour un client unique, un identifiant statique et unique (un ID)
  • MAIS, aussi des termes lisibles statiques et uniques

  • /technical-client/111855

  • /technical-client/111855-honda

  • UPRI : unique-id-plus-redundant-information

URI hackables ?

Hum ... nous verrons ça au niveau 3

Gérer les formats ?

  • Toute l'intelligence doit être stockée dans les paramètres
  • Pagination, filtre, tri, format, ...

  • NON : /clients.xml/0/10?sort=name
  • OUI : /clients?format=xml&sort=name&start=0&size=10

Versionner son API ?

http://company.com/api/v3.0/customer/123/v2.0/orders/4321/

See you at level 4 !


GET data/Equipements/get_equipements HTTP/1.1
Host: api.paris.fr

...
          

HTTP et Une URI = 1 Resource

LEVEL UP !

REST -> niveau 2


POST /lists/update-member.json HTTP/1.1
Host: us2.api.mailchimp.com

...
          

POST /list/interest-grouping-delete HTTP/1.1
Host: us2.api.mailchimp.com


...
          

Action dans l'URI

REST -> niveau 2

Pas d'actions dans l'URL, utilisez les méthodes HTTP

Qui connait toutes les méthodes HTTP ?

  • GET
  • POST
  • PUT
  • DELETE

  • Mais les méthodes HTTP, ce n'est pas QUE du CRUD

  • HEAD
  • OPTIONS
  • PATCH
  • TRACE
  • CONNECT

GET

Read du CRUD

Nullipotent/Nilpotent

Sert à récupérer des données

GET

  • /client
  • Récupère la collection contenant les URI correspondant à chaque client (ou les données directement)

  • /client/1
  • Récupère l'entité via ses données représentant le client

  • Client-serveur => la représentation <> la manière dont elle est persistée

  • Donnée unitaire + politique de cache adaptée = performance

GET /users/vbardales HTTP/1.1
Host: api.github.com

HTTP/1.1 200 OK

{
  "login": "vbardales",
  "id": 1446444,
  "url": "https://api.github.com/users/vbardales",
  "followers_url": "https://api.github.com/users/vbardales/followers",
  // ...
}
          

GET d'une entité


GET /users/vbardales/followers HTTP/1.1
Host: api.github.com

HTTP/1.1 200 OK

[
  {
    "login": "valdo404",
    "id": 175694,
    "url": "https://api.github.com/users/valdo404",
    "followers_url": "https://api.github.com/users/valdo404/followers"
  },
  {
    "login": "thomaroger",
    "id": 1062137,
    "url": "https://api.github.com/users/thomaroger",
    "followers_url": "https://api.github.com/users/thomaroger/followers"
  },
  // ...
]
          

GET d'une collection

Et comment on cache facilement, hein ?


GET /users/vbardales/followers HTTP/1.1
Host: api.github.com

HTTP/1.1 200 OK

[
  "https://api.github.com/users/valdo404",
  "https://api.github.com/users/thomaroger",
  "https://api.github.com/users/jeremymarc"
]
          

GET d'une collection

DELETE

Delete du CRUD

Idempotent

Sert à supprimer des données

DELETE

  • /client
  • Vide la collection

  • /client/1
  • Supprime l'entité

DELETE /repos/vbardales/AdmingeneratorGeneratorBundle HTTP/1.1
Host: api.github.com

HTTP/1.1 204 No Content
          

DELETE d'une entité

PUT

Create et Update du CRUD

Idempotent

Sert à écrire des données (ressource entière)

PUT

  • /client
  • Ecrase toute la collection de clients pour la remplacer par la nouvelle collection transmise

  • /client/1
  • Si l'entité existe, l'écrase, sinon, la crée

  • La ressource entière doit être transmise
  • Pas de mises à jour partielles

PUT /users/vbardales/followers HTTP/1.1
Host: api.github.com

[
  "https://api.github.com/users/valdo404",
  "https://api.github.com/users/jeremymarc"
]


HTTP/1.1 200 OK
...
          

PUT d'une collection

POST

2 comportements

Non-idempotent

POST

  • Cas 1 : provoque un changement de la ressource

  • /client/1/status
  • Si l'entité n'existe pas, la crée mais si elle existe, fait un autre traitement (405 Method Not Allowed)

  • /client/1/vote/18
  • Si l'entité existe et que le client n'a pas encore déposé d'entité 'vote', ajoute un vote, sinon, retire le vote du client

  • Pas fait pour mettre à jour une ressource

POST

  • Cas 2 : ajoute une entité à une collection sans précision de son futur identifiant

  • /client/1/invoice
  • Ajoute une entité 'invoice' à la collection de factures du client

POST /users/vbardales/followers HTTP/1.1
Host: api.github.com

https://api.github.com/users/thomaroger

HTTP/1.1 204 No Content
...
          

POST d'une nouvelle entité sur une collection

PATCH

Idempotent

Sert à mettre partiellement à jour des données

RFC 6902 - JavaScript Object Notation (JSON) Patch


PATCH /my/data/123 HTTP/1.1
Host: example.org
Content-Type: application/json-patch+json

[
  { "op": "test", "path": "/a/b/c", "value": "foo" },
  { "op": "remove", "path": "/a/b/c" },
  { "op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ] },
  { "op": "replace", "path": "/a/b/c", "value": 42 },
  { "op": "move", "from": "/a/b/c", "path": "/a/b/d" },
  { "op": "copy", "from": "/a/b/d", "path": "/a/b/e" }
]

HTTP/1.1 200 OK
...
          

GET /my/data/123 HTTP/1.1
Host: example.org

HTTP/1.1 200 OK

{
  "a": {
    "b": {
      "d": 42,
      "e": 42,
    }
  }
}
          

PATCH d'une ressource

OPTIONS

Nullipotent

Retourne les méthodes supportées pour une URI donnée


OPTIONS /my/data HTTP/1.1
Host: example.org

HTTP/1.1 204 No Content
Allow: HEAD,GET,PUT,DELETE,OPTIONS
          

OPTIONS sur une ressource

HEAD

Nullipotent


  • L'idée originale est :
  • Retourne l'entête du message obtenu lors d'un GET sans le corps de la requête

  • Moi je préfère :
  • Retourne un entête de message sans corps contenant certaines des informations obtenues lors d'un GET

GET /my/data?start=3&size=4 HTTP/1.1
Host: example.org

206 Partial Content

[
  "test4",
  "test5",
  "test6",
  "test7"
]
          

HEAD /my/data?start=3&size=4 HTTP/1.1
Host: example.org

HTTP/1.1 200 OK
Accept-Ranges: data
Content-Range: data 3-7/18
          

HEAD sur une ressource

HEAD

Vous en voulez plus ?

See you at level 3 !

Cas particulier :


POST /me?method=put HTTP/1.1
Host: api.viadeo.com

...
          

Paramètre method : pour les supports ne gérant pas toute la norme HTTP 1.1


POST /schema-instance HTTP/1.1
Host: www.soap.example.org
Content-Type: application/soap+xml
SOAPAction: "Some-URI"

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
  xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
  xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
  <m:GetStockPrice xmlns:m="http://www.example.org/stock">
    <m:StockName>IBM</m:StockName>
  </m:GetStockPrice>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

...
          

SOAP ne suit pas RESTv2 (utilisation abusive de POST)

LEVEL UP !

REST -> niveau 3


GET /users/vbardales HTTP/1.1
Host: api.github.com

HTTP/1.1 200 OK

{
  "login": "vbardales",
  "id": 1446444,
  "url": "https://api.github.com/users/vbardales",
  "followers_url": "https://api.github.com/users/vbardales/followers",
  // ...
}
          

Compatible RESTv3

REST -> niveau 3

Communément nommé RESTful


HATEOAS

Hypermedia as the Engine of Application State

HATEOAS

  • Je ne dois en aucun cas avoir à deviner ...
  • ... comment accéder à une ressource donnée
  • ... quelles sont les relations entre ressources et collections

  • Self-descriptive : mon index résume l'ensemble des ressources que j'expose et comment y accéder

Je suis sur une ressource, je veux y réaccéder ...



GET /cities/paris/events/29 HTTP/1.1
Host: api.humantalks.com

HTTP/1.1 200 OK

<?xml version="1.0" encoding="utf-8" ?>
<event>
  <id>29</id>
  <city>Paris</city>
  <date>2013-04-09T19:00:00Z</date>
  <link rel="self" href="/cities/paris/events/29.xml" />
  <link rel="city" href="/cities/paris/events.xml" />
  <link rel="talks" href="/events/29/talks.xml" />
</event>
          

Un lien self existe

Pratique cette balise link ...

Oui, mais en JSON ?

http://stateless.co/hal_specification.html

application/hal+json


{
  "_links": {
    "self": { "href": "/orders" },
    "next": { "href": "/orders?page=2" },
  },
  "currentlyProcessing": 14,
  "shippedToday": 20,
  "_embedded": {
    "ea:order": [{
      "_links": {
        "self": { "href": "/orders/123" },
        "ea:basket": { "href": "/baskets/98712" },
        "ea:customer": { "href": "/customers/7809" }
      },
      "total": 30.00,
      "currency": "USD",
      "status": "shipped"
    }]
  }
}

          

Verbeux ...

Oui, mais en JSON ?

Sinon, à la débrouille ...


GET /my/user/vbardales HTTP/1.1
Host: example.org

HTTP/1.1 200 OK

{
  "login": "vbardales",
  "_self": "https://api.github.com/users/vbardales",
  "name": "Virginie Bardales"
}
          

Un préfixe peut suffire

Je suis sur une collection paginée ...



GET /my/data?start=3&size=4 HTTP/1.1
Host: example.org

200 OK

{
  "_self": "http://example.org/my/data",
  "_collection": [
    "test4",
    "test5",
    "test6",
    "test7"
  ]
}
          

On rajoute un niveau d'indentation

Je suis sur une collection paginée ...



GET /my/data?start=3&size=4 HTTP/1.1
Host: example.org

206 Partial Content
Accept-Ranges: data
Content-Range: data 3-7/18

{
  "_self": "http://example.org/my/data",
  "_collection": [
    "test4",
    "test5",
    "test6",
    "test7"
  ]
}
          

Pas mal avec les Headers adaptés

Je suis sur une collection paginée ...



GET /my/data HTTP/1.1
Host: example.org
Range: data 3-

206 Partial Content
Accept-Ranges: data
Content-Range: data 3-7/18

{
  "_self": "http://example.org/my/data",
  "_collection": [
    "test4",
    "test5",
    "test6",
    "test7"
  ]
}
          

Pas mal pour libérer mon URL

Je suis sur une collection paginée ...



GET /my/data HTTP/1.1
Host: example.org
Range: data 3-

206 Partial Content
Accept-Ranges: data
Content-Range: data 3-7/18

{
  "_self": "http://example.org/my/data",
  "_relatedData": "http://example.org/my/related-data",
  "_collection": [
    "test4",
    "test5",
    "test6",
    "test7"
  ]
}
          

Dès que je rajoute d'autres relations ...

Je suis sur une collection paginée ...



GET /my/data HTTP/1.1
Host: example.org
Range: data 3-7

206 Partial Content
Accept-Ranges: data
Content-Range: data 3-7/18

{
  "_self": "http://example.org/my/data?start=3&size=4",
  "_relatedData": "http://example.org/my/related-data",
  "_page": {
    "total": 18,
    "next": "http://example.org/my/data?start=7&size=4",
    "prev": "http://example.org/my/data?start=0&size=4",
    "first": "http://example.org/my/data?start=0&size=4",
    "last": "http://example.org/my/data?start=14&size=4"
  }
  "_collection": [
    "test4",
    "test5",
    "test6",
    "test7"
  ]
}
          

Retour des paramètres d'URL

RFC 5988 - Web Linking



GET /my/data HTTP/1.1
Host: example.org
Range: data 3-7

206 Partial Content
Accept-Ranges: data
Content-Range: data 3-7/18
Link: <http://example.org/my/data?start=3&size=4>; rel="self",
<http://example.org/my/related-data>; rel="relatedData",
<http://example.org/my/data?start=7&size=4>; rel="next",
<http://example.org/my/data?start=0&size=4>; rel="prev",
<http://example.org/my/data?start=0&size=4>; rel="first",
<http://example.org/my/data?start=14&size=4>; rel="last"

[
  "test4",
  "test5",
  "test6",
  "test7"
]
          

Disparition du niveau d'indentation


GET /my/data HTTP/1.1
Host: example.org
Range: data 3-7

206 Partial Content
Accept-Ranges: data
Content-Range: data 3-7/18
Link: <http://example.org/my/data>; rel="self",
<http://example.org/my/related-data>; rel="relatedData"

[
  "test4",
  "test5",
  "test6",
  "test7"
]
          

Suppression des liens inutiles


GET /my/data HTTP/1.1
Host: example.org
Range: data 3-7

206 Partial Content
Accept-Ranges: data
Content-Range: data 3-7/18
Content-Location: http://example.org/my/data
Link: <http://example.org/my/related-data>; rel="relatedData"

[
  "test4",
  "test5",
  "test6",
  "test7"
]
          

Plus de lien self

Je crois que maintenant, ma méthode HEAD peut vraiment être utile ...

Canonical link


GET /my/city/19-pekin HTTP/1.1
Host: example.org
Range: data 3-7

200 OK
Content-Location: http://example.org/my/city/19-pekin

...
          

GET /my/city/19-beijing HTTP/1.1
Host: example.org
Range: data 3-7

200 OK
Content-Location: http://example.org/my/city/19-beijing
Link: <http://example.org/my/city/19-pekin>; rel="canonical"

...
          

UPRI = lien canonique


HEAD /my/data HTTP/1.1
Host: example.org
Range: data 18-

216 Requested Range Not Satisfiable
          

Codes status HTTP

LEVEL UP !

REST -> niveau 4


GET /my/data HTTP/1.1
Host: example.org
Range: data 3-7
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

...
          

Clients peu aptes à manipuler les Headers HTTP

Donc Headers HTTP peu utilisés

Mais dans le meilleur des mondes ...


GET /my/data HTTP/1.1
Host: example.org
Range: data 3-7
Accept: image/gif, image/jpeg, image/pjpeg, application/x-ms-application,
        application/vnd.ms-xpsdocument, application/xaml+xml,
        application/x-ms-xbap, application/x-shockwave-flash,
        application/x-silverlight-2-b2, application/x-silverlight,
        application/vnd.ms-excel, application/vnd.ms-powerpoint,
        application/msword, */*

...
          

Merci IE

Ne pas abuser des bonnes choses (pas de compression)

Trafic inutile

REST -> niveau 4

La revanche des Headers

ou la puissance des media-types !


GET /my/data HTTP/1.1
Host: example.org
Range: data 3-7
Accept: application/balloon+json

406 Not Acceptable
          

Accept fantaisiste

Versioning d'API


GET /my/data HTTP/1.1
Host: example.org
Range: data 3-7
Accept: application/org.example.data-v2+json

HTTP/1.1 200 OK
Content-Type: application/org.example.data-v2+json

...
          

Définit la version attendue

OUI MAIS ...

Lors d'un POST, je ne peux pas mettre ces headers-là

Oui, mais ... lors d'un POST, dernière version de l'API ?

OUI MAIS ...

Si je ne mets pas de Accept, que se passe-t-il ?

Une erreur HTTP 406 Not Acceptable ?

Par défaut la dernière version de l'API ?

CORS

Explicitement autoriser ces headers "custom"


GET /my/data HTTP/1.1
Host: example.org
Range: data 3-7

206 Partial Content
Accept-Ranges: data
Content-Range: data 3-7/18
Content-Location: http://example.org/my/data
Link: <http://example.org/my/related-data>; rel="relatedData"

[
  "test4",
  "test5",
  "test6",
  "test7"
]
          

API plutôt bien faite

LEVEL UP !

REST -> niveau 5

Et si ...

  • ... j'ai régulièrement besoin de connaitre la plus faible surface entre mes triangles et mes carrés ?
  • ... je veux savoir dans combien de temps le prochain bus passe ?

Je peux ...

  • ... écrire une requête complexe à base de filtres et d'ordres et récupérer le premier résultat
  • ... passer en RESTv5

REST -> niveau 5

Réintroduire du métier

Approche comportementale


GET /my/data HTTP/1.1
Host: example.org
Range: data 3-7

206 Partial Content
Accept-Ranges: data
Content-Range: data 3-7/18
Content-Location: http://example.org/my/data
Link: <http://example.org/my/related-data>; rel="relatedData",
<http://example.org/my/data/related-behavior>; rel="relatedBehavior",

[
  "test4",
  "test5",
  "test6",
  "test7"
]
          

Ajoutons du métier


POST /my/data/related-behavior HTTP/1.1
Host: example.org

...
          

Nouvelle dimension à POST

YOU WIN !

Les Frameworks

Express from scratch


var express = require('express');
var db = require('dbInitialization');

var app = express();
// setting up env (app.use(...))

// development only
if ('development' == app.get('env')) {
  app.use(express.errorHandler());
}

app.get('/user', function(req, res) {
  db.collection('user').find().toArray(function (err, items) {
    res.json(items);
  })
});
app.post('/user', function(req, res) { // ... });

// ...

// start server

          

A la main ...

Express & node-restful & mongoose

https://github.com/baugarten/node-restful


var express = require('express'),
    restful = require('node-restful'),
    mongoose = restful.mongoose;
var app = express();

// setting up env (app.use(...))

mongoose.connect("mongodb://localhost/resources");

var Resource = app.resource = restful.model('resource', mongoose.Schema({
    title: 'string',
    year: 'number',
  }))
  .methods(['get', 'post', 'put', 'delete']);

Resource.register(app, '/resources');

// start server
          

Pas RESTful ...

Flatiron's Restful

https://github.com/flatiron/restful


var flatiron = require('flatiron'),
    fixtures = require('../test/fixtures'),
    restful = require('../lib/restful'),
    resourceful = require('resourceful');

var app = module.exports = flatiron.app;

app.resources = {};
app.resources.Creature = fixtures.Creature;
app.resources.Album = fixtures.Album;

app.use(flatiron.plugins.http, {
  headers: {
    'x-powered-by': 'flatiron ' + flatiron.version
  }
});
app.use(restful);

// start server
          

Pas RESTful ...

Spumko's HAPI

https://github.com/spumko/hapi


var Hapi = require('hapi');
var db = require('dbInitialization');

// Create a server with a host and port
var server = Hapi.createServer('localhost', 8000);

// Add the route
server.route({
    method: 'GET',
    path: '/user',
    handler: function (request, reply) {
      db.collection('user').find().toArray(function (err, items) {
        reply(items);
      });
    }
});
// ...

// start server
          

Pas de génération automatique

Koa & Koa-route

http://koajs.com


var koa = require('koa');
var route = require('koa-route');
var db = require('dbInitialization');

var app = koa();
// setting up env (app.use(...))

app.use(route.get(function *() {
  this.body = (yield db.collection('user').find()).toArray();
});

// start server
          

<3 ES6

Conclusion

REST ou pas REST ?

Merci de votre écoute

Have a nice REST :D


Questions ?

Bibliographie

  • http://www.croes.org/gerald/blog/les-codes-statuts-http-a-connaitre/1021/#more-1021
  • http://www.figer.com/publications/REST.htm#.Uw2vdvl5N8F
  • http://developer.github.com/v3/
  • https://support.google.com/webmasters/answer/139394?hl=en
  • http://en.wikipedia.org/wiki/Representational_state_transfer
  • http://www.js-attitude.fr/2013/06/05/meilleures-pratiques-pour-vos-urls-verbes-http-et-apis/
  • http://en.wikipedia.org/wiki/Representational_state_transfer
  • http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol
  • http://developer.github.com/v3/repos/
  • http://dev.viadeo.com/documentation/tools-and-samples/advanced-api-use/http-method-parameter/

Bibliographie 2

  • http://apidocs.mailchimp.com/api/2.0/#lists-methods (MUAHAHA)
  • http://fr.wikipedia.org/wiki/Liste_des_codes_HTTP
  • http://en.wikipedia.org/wiki/SOAP
  • http://stackoverflow.com/questions/630453/put-vs-post-in-rest
  • https://tools.ietf.org/html/rfc6902
  • http://zacstewart.com/2012/04/14/http-options-method.html
  • http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
  • http://humantalks.com/talks/151-introduction-a-hateoas
  • http://en.wikipedia.org/wiki/HATEOAS
  • http://jeremybarthe.com/slides/humantalks-hateoas/#/5/3
  • http://stateless.co/hal_specification.html
  • http://www.newmediacampaigns.com/blog/browser-rest-http-accept-headers

Bibliographie 3

  • http://en.wikipedia.org/wiki/Content_negotiation
  • http://stackoverflow.com/questions/389169/best-practices-for-api-versioning
  • http://thereisnorightway.blogspot.fr/2011/02/versioning-and-types-in-resthttp-api.html
  • http://www.w3.org/Provider/Style/URI.html
  • http://coenraets.org/blog/2012/10/creating-a-rest-api-using-node-js-express-and-mongodb/
  • https://github.com/baugarten/node-restful
  • https://github.com/flatiron/restful
  • https://github.com/spumko/hapi
  • http://koajs.com
  • http://weblogs.asp.net/shijuvarghese/archive/2014/01/12/a-simple-crud-demo-with-koa-js.aspx