Fork me on GitHub

Frameworks web API HTTP, routage, templates

Application, requête, réponse

POST /url?a=b HTTP/1.1 Host: www.myhost.com Accept-Language: "fr;en" Content-Type: application/json { "func": "is_prime", "nums": [1,2,3,4,5,6,7,8] } "primes": [2,3,5,7] } { "status": "ok", Content-Type: application/json Content-Length: 40 Set-Cookie: sessid=0A5FD2 HTTP/1.1 200 OK Requête : query string entêtes corps de la requête méthode, url, cookies, ... Réponse : code d'état corps de la réponse entêtes, cookies, ... Application : router moteur de templates sessions interface BD middlewares ...

L’application

Silex (PHP)

require_once 'vendor/autoload.php';
$app = new Silex\Application();

$app->get();      // Le router
$app->post();
$app->match();

$app->run();      // Exécution

Express (Node.js)

var express = require('express');
var app = express();

app.get();        // Le router
app.post();
app.use();

app.listen(80);   // Exécution

L’objet requête

Silex

use Symfony\Component\HttpFoundation\Request;

$app->get('/', function(Request $req) {
	$req->query;      // Query string
	$req->request;    // corps de la requête
	$req->headers;    // entêtes HTTP
	$req->cookies;    // cookies
});

Express

app.use(express.query()).use(express.bodyParser()); // config

app.get('/', function(req, res) {
	req.query;        // query string
	req.body;         // corps de la requête
	req.headers;      // entêtes HTTP
	req.cookies;      // cookies
});

L’objet réponse (Silex)

use Symfony\Component\HttpFoundation\Response;

Écrire une réponse simple

return 'Hello world';

Envoyer un code d’état et des entêtes

return new Response(404, 'Not Found', headers);

Envoyer un fichier statique

return $app->sendFile('static-file.html');

Faire une rédirection

return $app->redirect('/other/path');

Envoyer des données au format JSON

return $app->json( array('a' => 'b') );

L’objet réponse (Node.js)

Écrire une réponse simple

res.send('Hello world');

Envoyer un code d’état et des entêtes

res.setHeader('Content-Type', 'text/plain');
res.send(404, 'Not Found');

Envoyer un fichier statique

res.sendfile('static-file.html');
res.download('static-attachment.mp3');

Faire une rédirection

res.redirect('/other/path');

Envoyer des données au format JSON

res.json({ 'a' : 'b' });

Anatomie de l’application

GET /path/to/resource/arg1/arg2 function($arg1, $arg2) { ... } <h1>Hello {{ user }}!</h1> SELECT * FROM user WHERE id=$arg1; HTTP/1.1 200 OK <h1>Hello toto!</h1> Router Gestionnaire Template engine Database Réponse

Le router

Le router fait l’association: méthode+URL → code à exécuter

$app->get('/url', function() {...});

Il peut aussi traduire une partie de l’URL en arguments de la fonction

$app->get('/url/{a1}/{a2}', function($a1, $a2) {
	...
});

En Express

app.get('/url/:a1/:a2', function(req, res) {
	console.log(req.params.a1);
});

Séparation des vues

Le problème : considérez ce gestionnaire

$res = '<html><head><title>Bla</title><body><table>';
foreach ($array as $k => $v) {
	$res .= "<tr><td>$k</td><td>$v</td></tr>";
}
return $res . '</table></body></html>';
  • Confusion entre logique et présentation,
  • Code difficile à lire et à organiser,
  • Syntaxe très lourde (répétition de la variable $res),
  • Pas possible de colorier la syntaxe HTML dans un éditeur,
  • Risques de sécurité…

Les templates naissent pour résoudre ces problèmes.

Templates

Templates

Un exemple de template

<!DOCTYPE html>
<html>
  <head>
    <title>Blabla</title>
  </head>
  <body>
    <h1>Bonjour {{ user }}</h1>
	
	{% include 'content.html' %}
  </body>
</html>
  • La valeur de la variable user est remplacée pour {{ user }} ;
  • Le contenu de content.html est inséré dans la sortie ;
  • Tout le reste est renvoyé à l’identique.

Langages de templating

Les langanges de templating permettent, en général, de

  • Remplacer des variables ({{ var }}) ;
  • Exécuter des tests ({% if %}) ;
  • Boucler sur des tableaux ({% for %}) ;
  • Inclure d’autres templates ({% include %}, {% block %}, {% extends %}) ;
  • Chaîner des transformations ({{ var | upper | strip }}) ;
  • Appliquer des opérateurs simples (mathématiques, logiques, comparaisons).

Quelques langages de templating

Twig

Substitution de variables, filtres

Hello {{ nom }}

Filtres

En majuscules : {{ nom | upper }}
Une liste : {{ list | join(', ') }}
{% filter upper %}
  {{ nom }}
{% endfilter %}

Contrôle

Conditionnel

{% if nom == 'toto' %}
  ...
{% endif %}

Boucle

{% for i in range(0, 10) %}
  Utilisateur : {{ users[i] }}
{% endfor %}
{% for u in users %}
  Utilisateur : {{ u }}
{% endfor %}

Modularité

Inclusion

{% include 'autre_template.html' %}

Macros

{% macro greet(nom) %}
  Bonjour Mr {{ nom }}
{% endmacro %}
{% from "macros.html" import greet %}

{{ greet('toto') }}

Héritage

Voici le template `main.html`
Le contenu de ces blocs est affiché tel quel

{% block titre %}
  Un titre quelconque
{% endblock %}

{% block pied %}
  Copyright Pinco Pallino
{% endblock %}
{% extends 'main.html' %}

Ce bloc va remplacer le bloc titre de `main.html`

{% block titre %}
  Commen hériter
{% endblock %}

Utiliser Twig: render

dans Silex

$app->register(new Silex\Provider\TwigServiceProvider(), 
               array('twig.path' => 'templates'));

$app->get('/', function(Application $app) {
	return $app['twig']->render('hello.html', array(
		'nom' => 'Toto'
	));
});

dans Express (s’applique aussi à d’autres langages de templating)

var twig = require('twig');
app.set('views', 'templates');   // où trouver les templates
app.set('view engine', 'html');      // à quelle extension
app.engine('html', twig.__express);  // associer twig

app.get('/', function(req, res) {
	res.render('hello.html', { 'nom' : 'Toto' });
});

Échappement

Échappement

  • La programmation web comporte le melange de plusieurs langages de programmation : HTML, CSS, JavaScript, PHP, templates, SQL, …
  • Chaque langange à ses caractères spéciaux. Par ex.: <, >, &, ', "

Considérez ce gestionnaire

function(Request $req) {
  return '<h1>' . $req->query->get('nom') . '</h1>';
}

Nom :

Les caractères <U , Z> sont interprétés comme la balise <U>.

Échappement HTML

HTML définit des séquences d’échappement pour ses caractères spéciaux, appelées character entities.

&lt; &gt; &amp; &quot; &apos;
< > & " '

Ces remplacements sont appliqués automatiquement par

  • La fonction htmlspecialchars() de PHP,
  • La fonction $app->escape() de Silex,
  • Twig et la majorité des autres moteurs de templates.

ATTENTION : n’utiliser que pour du HTML !

  • JSON : remplacer '\', "\",
  • JavaScript : comme JSON, mais avec beaucoup de soin !

Échappement dans Twig

Les remplacements {{ var }} sont échappés par défaut.

Désactiver l’échappement :

{% autoescape false %} {{ nom }} {% endautoescape %}
{{ nom | raw }}

Réactiver l’échappement :

{% autoescape 'html' %}{{ nom }}{% endautoescape %}
{% autoescape 'css' %}{{ nom }}{% endautoescape %}
{{ nom | escape }}
{{ nom | e }}

Nom :

Lectures

Silex

Express

Twig