Web Frameworks Web apps, HTTP API, Routing

Before dynamic pages

The earlier web servers just used to serve static files: HTML, images, etc.

CLIENT SERVER GET /index.html HTTP/1.1 HTTP/1.1 200 OK ... index.html
  • URLs correspond to a path in the server’s file system.

Static Generation

  • HTML files are assembled from various components,
  • They are compiled together before being installed on the server.

A modern example

menu.html content.md footer.pug index.html Markdown Pug
  • Markdown: Text → HTML transformation,
  • Pug: simplified syntax for HTML,
  • Perl: generic programming language.

Another example: These slides are statically generated (Markdown + Jekyll).

Web 1.0: dynamic pages

Document creation happens at the moment the HTTP request is received, on the fly.

GET /app.php HTTP/1.1 HTTP/1.1 200 OK app.php Scripting engine Authentication server Database XML template Generated HTML document

The server can:

  • Compile the document on the fly (like in static generation),
  • Interact with other servers (authentication, API),
  • Query databases,

Web 2.0: Web applications

Centered around user interaction.

GET /users.json HTTP/1.1 HTTP/1.1 200 OK Web Application Authentication Server Database XML template Generated JSON document
  • URLs no more correspond to files on the server,
  • A URL points to a virtual resource, signifies an action,
  • Web app execution done by
    • a web server (e.g., Apache+PHP, Tomcat+Java, …),
    • its own server (e.g., Node.js, …).

Web frameworks

A web framework is a library and a toolkit, helping to build web applications.

Some typical framework components

  • HTTP(S) API: parsing/writing of HTTP request/responses,
  • Router: defines a correspondence URL → Code to run,
  • Template engine: Templates → HTML pages generation,
  • Volatile storage: persistence, sessions, memcache,
  • Database abstraction,
  • Security mechanisms: injections, XSS, CSRF,
  • Caching, Internationalisation, …

Examples: Symfony (PHP), Zend (PHP), Node.js (JavaScript), Ruby on Rails (Ruby), Django (Python), Flask (Python), Tornado (Python), Java EE, …

Framework used in this course

Node.js

Event-driven web server based on Chrome’s JavaScript engine (V8 engine, written in C++)

  • Modules: Web server, HTTP API, Packet manager (npm).
  • Optional modules (developed by the community, distributed via npm): Web/REST frameworks, Sessions, Memcache, Templates engines, Database abstraction, WebSockets, …

… + Express

Web Micro-framework for Node.js (written en JavaScript)

  • Base components: Request/Response HTTP API, URL router, Query string parser, Static file server, …
  • Optional components (installed via npm): Request body parser, Cookie parser, Middlewares, CSRF protections, …

HTTP API: Application, request, response

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 Request: query string headers request body method, url, cookies, ... Response: status code response body headers, cookies, ... Application: router template engine sessions DB interface middlewares ...

The web application in Express

  1. Load the express module

    var express = require('express');
    
  2. Create the web application object

    var app = express();
    
  3. Define the handlers for the requests (Routing)

    app.get('/', ...);
    app.post('/form', ...);
    app.all('/old', ...);
    
  4. Let the application listen for connections (on port 80)

    app.listen(80);
    
  5. That’s all folks!

Anatomy of a handler

The router

The router associates: method+URL → code to run

app.get('/url', function(req, res) {
    ...
});

It can also translate part of the URL into arguments to the callback

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

The request object

var bodyParser = require("body-parser");
var cookieParser = require("cookie-parser");

// Configure the application
app
    .use(bodyParser.urlencoded({ extended: false }))
    .use(cookieParser());

app.get('/', function(req, res) {
    req.query;                    // query string
    req.body;                     // request body
    req.headers;                  // HTTP headers
    req.cookies;                  // cookies
});

The response object

Send a simple answer

res.send('Hello world');

Send a status code and some headers

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

Send a static file

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

Redirect to another page

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

Send JSON data

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

Hello world

var express = require('express');

var app = express();

app.get('/hello', function(req, res) {
    if (req.query.name) {
        res.send(`<h1>Hello, ${req.query.name}</h1>`);
    } else {
        res.send('<h1>Hello world!</h1>');
    }
});

app.listen(80);

Anatomy of the application

GET /path/foo/bar app.get('/path/:v1/:v2', function(req, res) { ... } <h1>Hello {{ user }}!</h1> SELECT * FROM user WHERE id=${req.params.v1}; HTTP/1.1 200 OK <h1>Hello foo!</h1> Router Handler Template engine Database Response

References

Fork me on GitHub