Express
Express is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications.
With a myriad of HTTP utility methods and middleware at your disposal, creating a robust API is quick and easy.
Express provides a thin layer of fundamental web application features, without obscuring Node features that you know and love.
Source: Express.js
Author of Express.js
Quick Start
- Install express with npm
- "Hello World"
- Run
- View in browser
- Get
Source: Express.js Hello World
$ npm install express --save
// FILENAME: app.js
var express = require('express');
var app = express();
app.get('/', function (req, res) {
res.send('Hello World!');
});
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('Example app listening at http://%s:%s', host, port);
});
$ node app.js
Example app listening at http://localhost:3000
Routing
Glossary
- Routing refers to the definition of end points (URIs) to an application and how it responds to client requests.
- In Express.js, a route is a combination of a URI, a HTTP request method (GET, POST, and so on), and one or more handlers for the endpoint.
- It takes the following structure app.METHOD(path, [callback...], callback), where app is an instance of express, METHOD is an HTTP request method, path is a path on the server, and callback is the function executed when the route is matched.
Source: Routing
Routing Method
|
|
|
Source: Express API
app.METHOD(path, callback [, callback ...])
- Express supports the following routing methods corresponding to the HTTP methods of the same names:
Routing Path
- Routing paths can be string patterns or regular expression with extracted parameters starting with colon ( : ).
- The extracted parameters are loaded automatically as properties of req.params.*
Source: Routing Paths
Path | Type | Params | Examples |
---|---|---|---|
"/path" | string pattern | /path | |
"/path/ab*cd" | string pattern | abcd, abxcd, abxxcd, abccd etc. | |
"/profile/:id" | string pattern | id | /profile/xxx, /profile/1234, /profile/abcd-1234 |
/\.md$/ | regular expression | /abcd.md, /path/1234.md; *NOT* match /abc.md/1234 |
Routing Handlers
- You can provide multiple callback functions that behave just like middleware to handle a request
- Route handlers can come in the form of a function, an array of functions, or various combinations of both
Source: Routing Handlers
var cb0 = function (req, res, next) {
console.log('CB0');
next();
}
var cb1 = function (req, res, next) {
console.log('CB1');
next();
}
var cb2 = function (req, res) {
res.send('Hello from C!');
}
app.get('/example/c', [cb0, cb1], cb2);
Basic Route Examples
// ROUTE - A
app.get('/', function(req, res) {
res.send('hello world');
});
// ROUTE - B
app.post('/', function (req, res) {
res.send('POST request to the homepage');
});
// ROUTE - C
app.get('/about', function (req, res) {
res.send('about');
});
// ROUTE - D
app.get('/ab*cd', function(req, res) {
res.send('ab*cd');
});
// ROUTE - E
app.get(/.*fly$/, function(req, res) {
res.send('/.*fly$/');
});
// ROUTE - F
app.get('/path/:id', function(req, res) {
res.send('/path/' + req.params.id);
});
// ROUTE - G
app.post('/ab(cd)?e', function (req, res) {
res.send('ab(cd)?e');
});
// ROUTE - H
app.get('/example/b', function (req, res, next) {
console.log('response will be sent by' +
' the next function ...');
next();
}, function (req, res) {
res.send('Hello from B!');
});
Response
Method | Description |
---|---|
res.download() | Prompt a file to be downloaded. |
res.end() | End the response process. |
res.json() | Send a JSON response. |
res.jsonp() | Send a JSON response with JSONP support. |
res.redirect() | Redirect a request. |
res.render() | Render a view template. |
res.send() | Send a response of various types. |
res.sendFile() | Send a file as an octet stream. |
res.sendStatus() | Set the response status code and send its string representation as the response body. |
Source: Routing
Middleware
Glossary
- Middleware is a function with access to the request object (req), the response object (res), and the next middleware in the application’s request-response cycle, commonly denoted by a variable named next.
- Middleware can
- Execute any code.
- Make changes to the request and the response objects.
- End the request-response cycle.
- Call the next middleware in the stack.
Source: Using Middleware
Middleware Pattern
Source: Middleware Pattern
Application-level Middleware
Source: Using Middleware
var app = express();
// a middleware with no mount path;
// gets executed for every request to the app
app.use(function (req, res, next) {
console.log('Time:', Date.now());
next();
});
// a middleware mounted on /user/:id;
// will be executed for any type of HTTP request to /user/:id
app.use('/user/:id', function (req, res, next) {
console.log('Request Type:', req.method);
next();
});
// a route and its handler function (middleware system)
// which handles GET requests to /user/:id
app.get('/user/:id', function (req, res, next) {
res.send('USER');
});
Bind application-level middleware to an instance of the app object with app.use() and app.METHOD(), where METHOD is is the HTTP method of the request that it handles, such as GET, PUT, POST, and so on, in lowercase.
Router-level Middleware
Source: Using Middleware
var app = express();
var router = express.Router();
// a middleware with no mount path, gets executed
// for every request to the router
router.use(function (req, res, next) {
console.log('Time:', Date.now());
next();
});
// a middleware sub-stack shows request info for
// any type of HTTP request to /user/:id
router.use('/user/:id', function(req, res, next) {
console.log('Request URL:', req.originalUrl);
next();
}, function (req, res, next) {
console.log('Request Type:', req.method);
next();
});
Router-level middleware works just like application-level middleware except it is bound to an instance of express.Router().
// a middleware sub-stack which handles GET
// requests to /user/:id
router.get('/user/:id', function (req, res, next) {
// if user id is 0, skip to the next router
if (req.params.id == 0) next('route');
// else pass the control to the next middleware
// in this stack
else next();
}, function (req, res, next) {
// render a regular page
res.render('regular');
});
// handler for /user/:id which renders a special page
router.get('/user/:id', function (req, res, next) {
console.log(req.params.id);
res.render('special');
});
// mount the router on the app
app.use('/', router);
Builtin Middlewares
Source: Using Middleware
- express.static(root, [options]) - serving the static assets of an Express application
Property | Description | Type | Default |
---|---|---|---|
dotfiles |
Option for serving dotfiles. Possible values are “allow”, “deny”, and “ignore” | String | “ignore” |
etag |
Enable or disable etag generation | Boolean | true |
extensions |
Sets file extension fallbacks. | Array | [] |
index |
Sends directory index file. Set false to disable directory indexing. |
Mixed | “index.html” |
lastModified |
Set the Last-Modified header to the last modified date of the file on the OS. Possible values are true or false . |
Boolean | true |
maxAge |
Set the max-age property of the Cache-Control header in milliseconds or a string in ms format | Number | 0 |
redirect |
Redirect to trailing “/” when the pathname is a directory. | Boolean | true |
setHeaders |
Function for setting HTTP headers to serve with the file. | Function |
var options = {
dotfiles: 'ignore',
etag: false,
extensions: ['htm', 'html'],
index: false,
maxAge: '1d',
redirect: false,
setHeaders: function (res, path, stat) {
res.set('x-timestamp', Date.now());
}
}
app.use(express.static('public', options));
Third-Party Middlewares
Source: Third-Party Middlewares
- List of third-party middlewares
- body-parser: populate the req.body property with the parsed body or provide an error to the callback
- cookie-parser: Parse Cookie header and populate req.cookies with an object keyed by the cookie names.
- cookie-session: Simple cookie-based session middleware.
- Example - use cookie-parser
$ npm install cookie-parser
var express = require('express');
var app = express();
var cookieParser = require('cookie-parser');
// load the cookie parsing middleware
app.use(cookieParser());
WebSocket
WebSocket is a protocol providing full-duplex communication channels over a single TCP connection.
The WebSocket API is a Candidate Recommendation of W3C standard.
Source: Wikipedia - WebSocket
WebSocket Demo - Echo
- Open up WebSocket connection
- ws: - protocol of WebSocket for unencrypted transportation; and wss: protocol is used for encrypted transportation like https:
- ['soap', 'xmpp'] - optional subprotocols on IANA registry
- Listen to the event handlers
- Send message to server
Source:
var connection = new WebSocket('ws://html5rocks.websocket.org/echo', ['soap', 'xmpp']);
// When the connection is open, send some data to the server
connection.onopen = function () {
connection.send('Ping'); // Send the message 'Ping' to the server
};
// Log errors
connection.onerror = function (error) {
console.log('WebSocket Error ' + error);
};
// Log messages from the server
connection.onmessage = function (e) {
console.log('Server: ' + e.data);
};
// Sending String
connection.send('your message');
WebSocket Protocol - 13 RFC6455
- Client sends handshake message to server:
- and server responses with following:
- then keep connection and exchange data in frames
- ... until connection closed
Source: RFC6455
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat
Relationship to TCP and HTTP
- The WebSocket Protocol is an independent TCP-based protocol. Its only relationship to HTTP is that its handshake is interpreted by HTTP servers as an Upgrade request.
- By default, the WebSocket Protocol uses port 80 for regular WebSocket connections and port 443 for WebSocket connections tunneled over Transport Layer Security (TLS) [RFC2818].
Source: RFC6455
WebSocket on Server Side
- Node.js modules for WebSocket server
- Example of WebSocket server using ws
Source: WS
var WebSocketServer = require('ws').Server
, wss = new WebSocketServer({ port: 8080 });
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
console.log('received: %s', message);
});
ws.send('something');
});
A Chat Server
Source: Why Use Node.js
RESTful Web Service
Representational State Transfer
Glossary
- REST defines a set of architectural principles by which you can design Web services that focus on a system's resources, including how resource states are addressed and transferred over HTTP by a wide range of clients written in different languages.
- RESTful web service follows four basic design principles
- Use HTTP methods explicitly.
- Be stateless.
- Expose directory structure-like URIs.
- Transfer XML, JavaScript Object Notation (JSON), or both.
Source: RESTful Web Services
Use HTTP methods explicitly
- REST asks developers to use HTTP methods explicitly and in a way that's consistent with the protocol definition. This basic REST design principle establishes a one-to-one mapping between create, read, update, and delete (CRUD) operations and HTTP methods.
- According to this mapping:
- To create a resource on the server, use POST.
- To retrieve a resource, use GET.
- To change the state of a resource or to update it, use PUT.
- To remove or delete a resource, use DELETE.
Source: RESTful Web Services
Be stateless
- A complete, independent request doesn't require the server, while processing the request, to retrieve any kind of application context or state.
- A REST Web service application (or client) includes within the HTTP headers and body of a request all of the parameters, context, and data needed by the server-side component to generate a response.
- Statelessness in this sense improves Web service performance and simplifies the design and implementation of server-side components because the absence of state on the server removes the need to synchronize session data with an external application.
Source: RESTful Web Services
Be stateless - Example
Source: RESTful Web Services
Stateful Web Service
Stateless Web Service
Expose directory structure-like URIs
- REST Web service URIs should be intuitive to the point where they are easy to guess. The structure of a URI should be straightforward, predictable, and easily understood.
- One way to achieve this level of usability is to define directory structure-like URIs.
- Some additional guidelines to make note of while thinking about URI structure for a RESTful Web service are:
- Hide the server-side scripting technology file extensions (.jsp, .php, .asp), if any, so you can port to something else without changing the URIs.
- Keep everything lowercase.
- Substitute spaces with hyphens or underscores (one or the other).
- Avoid query strings as much as you can.
- Instead of using the 404 Not Found code if the request URI is for a partial path, always provide a default page or resource as a response.
http://www.myservice.org/discussion/{year}/{day}/{month}/{topic}
Source: RESTful Web Services
Transfer XML, JSON, or both
- The last set of constraints that goes into a RESTful Web service design has to do with the format of the data that the application and service exchange in the request/response payload or in the HTTP body. This is where it really pays to keep things simple , human-readable , and connected .
- Common MIME types used by RESTful services
MIME-Type | Content-Type |
---|---|
JSON | application/json |
XML | application/xml |
XHTML | application/xhtml+xml |
Source: RESTful Web Services
Questions?
What we learned
-
Express - a lightweight web application framework for Node.js
-
WebSocket - a protocol for persistent full-duplex TCP communication
-
RESTful - principles of developing web services
Source: Why Git?
Server Side JavaScript - Node.js (Part2)
By Haili Zhang
Server Side JavaScript - Node.js (Part2)
- 1,208