Express js fast server. Node JS & Express Basics (III)

$ npm install express

or, to have access to the express command, install globally:

$ npm install -g express

Fast start

The easiest way to get started with Express is to run the express command, which will generate the application:

Creating an application:

$ npm install -g express $ express /tmp/foo && cd /tmp/foo

Installing dependencies:

$ npm install -d

Starting the server:

Creating a server

To create an instance of express.HTTPServer, simply call the createServer() method. With our application instance, we can specify routes based on HTTP methods, in this example app.get() .

var app = require("express").createServer(); app.get("/", function(req, res)( res.send("hello world"); )); app.listen(3000);

Creating an HTTPS server

To initialize express.HTTPSServer , we perform the same steps as above, but we also pass an options object containing the key, certificate and other parameters that are described in the NodeJS https module documentation.

var app = require("express").createServer(( key: ... ));

Configuration

Express supports arbitrary environments, such as production and development. Developers can use the configure() method to add features needed for a given environment. When configure() is called without an environment name, it will fire in any environment before any configure in which the environment is specified will fire.

In the example below, we simply use the dumpExceptions option and, in development mode, respond to the client with a stack trace of the exception. In both modes, we use the methodOverride and bodyParser layers. Note the use of app.router , which itself allows routes to be mounted - otherwise they are mounted the first time app.get() , app.post() , etc. are called.

app.configure(function())( app.use(express.methodOverride()); app.use(express.bodyParser()); app.use(app.router); )); app.configure("development", function())( app.use(express.static(__dirname + "/public")); app.use(express.errorHandler(( dumpExceptions: true, showStack: true ))); ) ); app.configure("production", function())( var oneYear = 31557600000; app.use(express.static(__dirname + "/public", ( maxAge: oneYear ))); app.use(express.errorHandler()) ; ));

For environments with similar settings, you can pass multiple environment names:

app.configure("stage", "prod", function())( // config ));

For internal and arbitrary settings, Express has the methods set(key[, val]) , enable(key) , disable(key) :

app.configure(function () ( app.set("views", __dirname + "/views"); app.set("views"); // => "/absolute/path/to/views" app.enable ("some feature"); // same as app.set("some feature", true); app.disable("some feature"); // same as app.set("some feature", false) ; app.enabled("some feature") // => false ));

To set the environment we can set the NODE_ENV environment variable. For example:

$ NODE_ENV=production node app.js

This is very important because many caching mechanisms are only enabled in a production environment.

Settings

Out of the box Express supports the following settings:

  • home is the application's base path, which is used for res.redirect() as well as transparent support for mounted applications.
  • views is the root directory of views. By default current_folder/views
  • view engine - default template engine for views called without a file extension.
  • view options - an object reflecting global view options
  • view cache - enable view caching (enabled in production environment)
  • case sensitive routes - enable case sensitive routes
  • strict routing - if enabled, trailing slashes are no longer ignored
  • jsonp callback - allow res.send() method to transparently support JSONP

Routing

Express uses HTTP methods to provide a meaningful, expressive routing API. For example, we want the search for /user/12 to display the profile of the user with id=12 . To do this, we define the route below. The values ​​associated with named fields are available in the res.params object.

app.get("/user/:id", function(req, res)( res.send("user " + req.params.id); ));

A route is simply a string that is compiled into a regular expression inside the engine. For example, when /user/:id is compiled, the result is a regular expression like this:

\/user\/([^\/]+)\/?

You can also immediately pass a regular expression. But since groups are not named in regular expressions, they can be reached in req.params by numbers. So the first group goes into req.params , the second into req.params , etc.

app.get(/^\/users?(?:\/(\d+)(?:\.\.(\d+))?)?/, function(req, res)( res.send(req.params ); ));

Now let's take curl and send a request to the above route:

$ curl http://dev:3000/user $ curl http://dev:3000/users $ curl http://dev:3000/users/1 ["1",null] $ curl http://dev: 3000/users/1..15 ["1","15"]

Below are some example routes and paths that might match them:

"/user/:id" /user/12 "/users/:id?" /users/5 /users "/files/*" /files/jquery.js /files/javascripts/jquery.js "/file/*.*" /files/jquery.js /files/javascripts/jquery.js "/ user/:id/:operation?" /user/1 /user/1/edit "/products.:format" /products.json /products.xml "/products.:format?" /products.json /products.xml /products "/user/:id.:format?" /user/12 /user/12.json

For example, we can POST some JSON and respond with the same JSON using the bodyParser layer, which can parse a JSON request (as well as other requests) and place the response in req.body:

var express = require("express"), app = express.createServer(); app.use(express.bodyParser()); app.post("/", function(req, res) ( res.send(req.body); )); app.listen(3000);

As a rule, we use a “dumb” field (for example, /user/:id), which has no restrictions. But if we, for example, want to limit the user ID to only numeric characters, we can use /user/:id(+) . This design will not work if the field value contains non-numeric characters.

Transferring control to another route

By calling the third argument, next() , you can pass control to the next route. If a match is not found, control is passed back to Connect and the layers continue to be called in the order in which they were enabled using use() . Multiple routes sharing the same path also work. They are simply called one at a time until one of them responds instead of calling next() .

app.get("/users/:id?", function(req, res, next) ( var id = req.params.id; if (id) ( // do something ) else ( next(); ) )); app.get("/users", function(req, res) ( // do something else ));

The app.all() method is useful if you want to perform the same logic for all HTTP methods. Below we use this method to retrieve a user from the database and assign it to req.user.

var express = require("express"), app = express.createServer(); var users = [( name: "tj" )]; app.all("/user/:id/:op?", function(req, res, next) ( req.user = users; if (req.user) ( next(); ) else ( next(new Error( "cannot find user " + req.params.id)); app.get("/user/:id", function(req, res) ( res.send("viewing " + req.user.name); )); app.get("/user/:id/edit", function(req, res) ( res.send("editing " + req.user.name); )); app.put("/user/:id", function(req, res) ( res.send("updating " + req.user.name); )); app.get("*", function(req, res) ( res.send("what???", 404); )); app.listen(3000);

Interlayers

Connect framework layers can be passed to express.createServer() in the same way as if a regular Connect server were used. For example:

var express = require("express"); var app = express.createServer(express.logger(), express.bodyParser());

You can also use use() . This makes it more convenient to add layers inside configure() blocks, which is more progressive.

app.use(express.logger(( format: ":method:url" )));

Typically with Connect layers we can connect Connect like this:

var connect = require("connect"); app.use(connect.logger()); app.use(connect.bodyParser());

This is not entirely convenient, so Express re-exports the Connect layers:

app.use(express.logger()); app.use(express.bodyParser());

The order of the layers matters. So, when Connect receives a request, the first layer added via createServer() or use() is executed. It is called with three parameters: request, response, and a callback function, usually called next. when next() is called, control is passed to the second layer, etc. This is important to take into account, since many layers depend on each other. For example, methodOverride() calls req.body.method to overload an HTTP method, and bodyParser() parses the request body to fill req.body . Another example is cookie parsing and session support - first you need to call use() on cookieParser() , then on session() .

Many Express applications may have the line app.use(app.router) . This may seem strange, but this is simply to explicitly specify the layer that includes all the routes we created. This layer can be included in any order, although by default it is included at the end. By changing its position, you can control the order of its execution. For example, we need an error handler that will fire after all other layers and display any exception passed to it using next() . Or it may be necessary to lower the execution order of the layer serving static files to allow other routes to intercept requests for such files and, for example, count the number of downloads, etc. Here's what it might look like:

app.use(express.logger(...)); app.use(express.bodyParser(...)); app.use(express.cookieParser(...)); app.use(express.session(...)); app.use(app.router); app.use(express.static(...)); app.use(express.errorHandler(...));

First we add logger() - it will wrap the req.end() method to give us response rate data. Then we parse the request body (if there is one), then the cookies, then the session, so that req.session is already defined when we get to the routes in app.router . If, for example, a GET request to /javascripts/jquery.js is handled by routes and we don't call next() , then the static() layer will never receive that request. However, if we define a route as shown below, it will be possible to record statistics, reject downloads, charge downloads, etc.

var downloads = (); app.use(app.router); app.use(express.static(__dirname + "/public")); app.get("/*", function(req, res, next) ( var file = req.params; downloads = downloads || 0; downloads++; next(); ));

Layer routes

Routes can use routing layers by passing additional callbacks (or arrays) to the method. This is useful if you need to restrict access or load any data before using a route, etc.

Typically, asynchronous data retrieval may look something like the one shown below (here we take the:id parameter and load the user data).

app.get("/user/:id", function(req, res, next) ( loadUser(req.params.id, function(err, user) ( if (err) return next(err); res.send( "Viewing user " + user.name);

To adhere to the DRY principle and improve code readability, you can organize such logic using layers. As you can see, by abstracting the logic using layers, you can both achieve reuse of layers and make the route code more beautiful.

function loadUser(req, res, next) ( // here we load the user from the database var user = users; if (user) ( req.user = user; next(); ) else ( next(new Error("Failed to load user " + req.params.id)); ) ) app.get("/user/:id", loadUser, function(req, res) ( res.send("Viewing user " + req.user.name) ; ));

Multiple routing layers can be added and they will be executed sequentially to provide different logic, such as restricting access to a user account. In the example below, only an authorized user can edit their account.

function andRestrictToSelf(req, res, next) ( req.authenticatedUser.id == req.user.id ? next() : next(new Error("Unauthorized")); ) app.get("/user/:id/ edit", loadUser, andRestrictToSelf, function(req, res) ( res.send("Editing user " + req.user.name); ));

Recognizing that layers are just functions, you can write a function that returns a layer (to provide an even more expressive and flexible solution), as shown below.

function andRestrictTo(role) ( return function(req, res, next) ( req.authenticatedUser.role == role ? next() : next(new Error("Unauthorized")); ) ) app.del("/user/ :id", loadUser, andRestrictTo("admin"), function(req, res) ( res.send("Deleted user " + req.user.name); ));

Frequently used “stacks” of layers can be passed as arrays of arbitrary depth and tree structure (they will be applied recursively):

var a = , b = , all = ; app.get("/foo", a, function() ()); app.get("/bar", a, function() ()); app.get("/", a, middleware3, middleware4, function() ()); app.get("/", a, b, function() ()); app.get("/", all, function() ());

The full example can be found in the repository.

There are times when you need to skip the remaining route layers in the stack, but continue executing the next routes. To do this, call next() with the route argument: next("route") . If there are no routes left to execute, Express will respond with a 404 Not Found error.

HTTP methods

We've already used app.get() a number of times, but Express also provides other HTTP methods - app.post() , app.del() , etc.

The most common use case for POST is when submitting a form. In the example below we are simply making an HTML form. And then control will be transferred to the route that we will define in the next example.

By default, Express doesn't know what to do with the request body, so we must add a bodyParser() layer that will parse the request body encoded in application/x-www-form-urlencoded or application/json and put the parsing results in req .body . To do this we have to say use() like below:

app.use(express.bodyParser());

Now the below route will access the req.body.user object, which will have name and email properties:

app.post("/", function(req, res) ( console.log(req.body.user); res.redirect("back"); ));

If the form uses methods such as PUT, you can use a hidden input called _method, which allows you to change the HTTP method. To achieve this, we must first enable a methodOverride() layer, which will be placed after bodyParser(), which will allow it to use the req.body containing the fields of the submitted form.

app.use(express.bodyParser()); app.use(express.methodOverride());

These layers are not enabled by default, because Express does not necessarily have full functionality right away. Depending on the needs of the application, you may not need to use them. And then the PUT and DELETE methods will still be available, but directly. At the same time, methodOverride is an excellent solution for HTML forms. Below is an example of using the PUT method:

app.put("/", function() ( console.log(req.body.user); res.redirect("back"); ));

Error processing

Express has an app.error() method that accepts any exceptions thrown by routes or passed as next(err) . Below is an example of how to serve multiple pages using a homemade NotFound exception:

function NotFound(msg) ( this.name = "NotFound"; Error.call(this, msg); Error.captureStackTrace(this, arguments.callee); ) NotFound.prototype.__proto__ = Error.prototype; app.get("/404", function(req, res) ( throw new NotFound; )); app.get("/500", function(req, res) ( throw new Error("keyboard cat!"); ));

You can call app.error() multiple times as shown below. Here we check for instanceof NotFound and show a 404 page, or pass control to the next error handler.

Note that these handlers can be defined anywhere, since they will still be placed below the route handlers in listen() . This allows them to be defined within configure() blocks, so that exceptions can be handled differently depending on the current environment.

app.error(function(err, req, res, next) ( if (err instanceof NotFound) ( res.render("404.jade"); ) else ( next(err); ) ));

For the sake of simplicity, we assume here that all errors have a code of 500, but you can change this as you wish. For example, when Node does file system operations, we can get an error object with a field error.code = ENOENT, which means “file or directory not found”, we can use this in an error handler and show the corresponding page.

app.error(function(err, req, res) ( res.render("500.jade", ( error: err )); ));

Applications can also use Connect's errorHander layer to handle exceptions. For example, if you need to show exceptions in stderr in the development environment, you can do this:

app.use(express.errorHandler(( dumpExceptions: true )));

Also, during development, we may need cool HTML pages that show exceptions thrown or thrown. In this case, you need to set showStack to true:

app.use(express.errorHandler(( showStack: true, dumpExceptions: true )));

The errorHandler layer also responds in JSON if an Accept: application/json header is passed by the client, which is useful for developing AJAX applications.

Pre-processing route parameters

Pre-processing route parameters can significantly improve the readability of an application through explicit data loading and request URL validation. For example, if you are constantly retrieving some data for certain queries (eg loading user data for /user/:id), you could do something like this:

app.get("/user/:userId", function(req, res, next) ( User.get(req.params.userId, function(err, user) ( if (err) return next(err); res. send("user " + user.name ));

With preconditions, we can attach callback functions to our query parameters that would perform validation, restrict access, or even load data from the database. In the example below, we call app.param() with the name of the parameter we want to attach a callback to. As you can see, we receive an id argument, which contains the name of the field. This way we load the user object and do the usual error handling and a simple call to next() to pass control to the next precondition or route handler.

app.param("userId", function(req, res, next, id) ( User.get(id, function(err, user) ( if (err) return next(err); if (!user) return next( new Error("failed to find user"); req.user = user());

The above steps, as already mentioned, significantly improve the readability of the code and make it easy to use the same logic in different places in the application:

app.get("/user/:userId", function(req, res) ( res.send("user " + req.user.name); ));

Rendering Views

View file names follow the scheme (name). (engine), where (engine) is the name of the template engine module that must be connected. For example, the layout.ejs view tells the view system to do require("ejs") . To integrate with Express, the loadable module must export a method, exports.compile(str, options) , and return a function. To change this behavior, you can use the app.register() method - it allows you to associate file extensions with specific engines. For example, you can make foo.html rendered by the engine ejs.

Below is an example using Jade to render index.html . And since we are not using layout:false , the rendered content of the index.jade view will be passed as a local body variable to the layout.jade view.

app.get("/", function(req, res) ( res.render("index.jade", ( title: "My Site" )); ));

Setting up the view engine allows you to specify the default template engine. So, for example, when using Jade you can do this:

app.set("view engine", "jade");

which will allow us to render like this:

res.render("index");

But not like this:

res.render("index.jade");

When the template engine is installed via the view engine, file extensions are not needed. However, we can still use several template engines at once:

res.render("another-page.ejs");

Express also has a view options setting that will be applied every time the view is rendered. For example, if you don’t use layouts that often, you can write it like this:

app.set("view options", ( layout: false ));

Which can then be overloaded if necessary in a call to res.render() :

res.render("myview.ejs", ( layout: true ));

When you need a different layout, you can also specify the path. For example, if we have the view engine set to jade and the layout file is called ./views/mylayout.jade , we can simply pass:

res.render("page", ( layout: "mylayout" ));

Otherwise, you can pass the file extension:

res.render("page", ( layout: "mylayout.jade" ));

Paths can also be absolute:

res.render("page", ( layout: __dirname + "/../../mylayout.jade" ));

A good example is specifying non-standard opening and closing engine tags ejs:

app.set("view options", ( open: "((", close: "))" ));

View Fragments

The Express view system has built-in support for fragments and collections, a kind of mini-view. For example, instead of looping through the view to display a list of comments, you can simply use a collection fragment:

partial("comment", (collection: comments));

If other options or local variables are not needed, then you can skip the object and just pass the data array. The example below is equivalent to the previous one:

partial("comment", comments);

When using collections, we have several “magic” local variables:

  • firstInCollection - true if this is the first object
  • indexInCollection - index of the object in the collection
  • lastInCollection - true if this is the last object
  • collectionLength - collection length

Local variables passed or generated take precedence, but local variables passed to the parent view are also available to the child view. So for example, if we render a view using partial("blog/post", post) and it produces a local variable post , and the view that called this function had a local variable user , then user will also be visible in the blog/post view.

See res.partial() for more documentation.

Note: Use collections carefully, since rendering an array of 100 elements means rendering 100 views. For simple collections, it is better to loop through the view rather than using collections. This way the load will be less.

Search for views

Views are searched relative to the parent view. For example, if we have a view views/user/list.jade and inside it we call partial("edit") , the system will try to load the view views/user/edit.jade , whereas partial("../messages") will result to download views/messages.jade

The view system also allows you to create index files. For example, we can call res.render("users") and this can load both views/users.jade and views/users/index.jade .

You can also use index files from a view in the same directory. So calling partial("users") can access the view ../users/index instead of calling partial("index") .

Template engines

Below are a few template engines commonly used with Express:

  • E.J.S.- built-in JavaScript
  • CoffeeKup- template based CoffeeScript
  • jQuery Templates for Node

Session support

Session support can be enabled using Connect's session layer. Also for this we need an overlying cookieParser layer, which will parse cookies and place them in req.cookies.

app.use(express.cookieParser()); app.use(express.session(( secret: "keyboard cat" )));

By default, the session layer uses Connect's in-memory storage, but there are many other solutions. For example connect-redis supports session storage in Redis. Here's how to use it:

var RedisStore = require("connect-redis")(express); app.use(express.cookieParser()); app.use(express.session(( secret: "keyboard cat", store: new RedisStore )));

Now the req.session and req.sessionStore properties will be available from all routes and subsequent layers. The req.session properties are automatically saved upon response. Here's how to organize your cart:

var RedisStore = require("connect-redis")(express); app.use(express.bodyParser()); app.use(express.cookieParser()); app.use(express.session(( secret: "keyboard cat", store: new RedisStore ))); app.post("/add-to-cart", function(req, res) ( // let's say we passed several objects from the form // use bodyParser() for this var items = req.body.items; req.session. items = items; res.redirect("back" )); app.get("/add-to-cart", function(req, res) ( // When we redirect to GET /add-to-cart // we can check req.session.items && req.session.items .length // to print our message if (req.session.items && req.session.items.length) ( req.flash("info", "You have %s items in your cart", req.session.items. length); res.render("shopping-cart");

The req.session object also has Session.touch() , Session.destroy() , Session.regenerate() methods for manipulating sessions. For more complete information, see the Connect Session documentation.

Migration Guide

Developers who have worked with Express 1.x can refer to the migration guide to get their applications working with Express 2.x, Connect 1.x, and Node 0.4.x.

Request

req.header(key[, defaultValue])

Get the key request header (case insensitive) with an optional default DefaultValue:

req.header("Host"); req.header("host"); req.header("Accept", "*/*");

The Referrer and Referer headers are a special case; both constructs will work:

// sent the header "Referrer: http://google.com" req.header("Referer"); // => "http://google.com" req.header("Referrer"); // => "http://google.com"

req.accepts(type)

Checks whether the Accept header is passed and whether it matches the given type.

When the Accept header is missing, true is returned. Otherwise, the type matches and then the subtypes are checked. It is possible to pass "html" which is internally converted to "text/html" using a MIME lookup table.

// Accept: text/html req.accepts("html"); // => true // Accept: text/*; application/json req.accepts("html"); req.accepts("text/html"); req.accepts("text/plain"); req.accepts("application/json"); // => true req.accepts("image/png"); req.accepts("png"); // => false

req.is(type)

Checks the incoming request for the presence of a Content-Type header and matches the specified MIME type.

// Let Content-Type: text/html; charset=utf-8 req.is("html"); req.is("text/html"); // => true // Let the Content-Type now be application/json req.is("json"); req.is("application/json"); // => true req.is("html"); // => false

In Express, you can register your own callbacks for various request checks. For example, let's say we need to do a nice check to see if the incoming request is an image. To do this, you can register the "an image" callback:

app.is("an image", function(req) ( return 0 == req.headers["content-type"].indexOf("image"); ));

Now you can use it inside route handlers to check the Content-Type of the form "image/jpeg", "image/png", etc.

app.post("/image/upload", function(req, res, next) ( if (req.is("an image")) ( // perform certain actions ) else ( next(); ) ));

Don't forget that this method doesn't just apply to Content-Type - you can do any kind of checks.

You can also use wildcard characters. This will simplify our image example. Here we will only check the type:

req.is("image/*");

We can also check the subtype as shown below. Here the check will return true in the cases of "application/json" and "text/json" .

req.is("*/json");

req.param(name[, default])

Returns the value of the parameter name or - if it does not exist - default .

Checks route parameters (req.params), for example /user/:id

Checks query string parameters (req.query), for example, ?id=12

Checks the urlencoded parameters of the request body (req.body), for example, id=12

To receive urlencoded request body parameters, a req.body object must exist. To do this, enable the bodyParser() layer.

req.get(field, param)

Gets the header field parameter. The default is an empty string.

req.get("content-disposition", "filename"); // => "something.png" req.get("Content-Type", "boundary"); // => "--foo-bar-baz"

req.flash(type[, msg])

Queues the popup message.

req.flash("info", "email sent"); req.flash("error", "email delivery failed"); req.flash("info", "email re-sent"); // => 2 req.flash("info"); // => ["email sent", "email re-sent"] req.flash("info"); // => req.flash(); // => ( error: ["email delivery failed"], info: )

Pop-up messages can also use format strings. The default string "%s" is available:

req.flash("info", "email delivery to _%s_ from _%s_ failed.", toUser, fromUser);

req.isXMLHttpRequest

Also abbreviated req.xhr. Checks the X-Requested-With header to see if the request was made using an XMLHttpRequest:

req.xhr req.isXMLHttpRequest

Response

res.header(key[, val])

Gets or sets the response header.

res.header("Content-Length"); // => undefined res.header("Content-Length", 123); // => 123 res.header("Content-Length"); // => 123

res.charset

Sets the encoding of the following Content-Type headers. For example, res.send() and res.render() will default to "utf8" and we can explicitly set the encoding before rendering the template:

res.charset = "ISO-8859-1"; res.render("users");

or before replying with res.send() :

res.charset = "ISO-8859-1"; res.send(str);

or using Node's built-in res.end() :

res.charset = "ISO-8859-1"; res.header("Content-Type", "text/plain"); res.end(str);

res.contentType(type)

Sets the Content-Type response header.

var filename = "path/to/image.png"; res.contentType(filename); // Content-Type is now "image/png"

You can also set Content-Type with the following string:

res.contentType("application/json");

Or just the file extension (without the leading dot):

res.contentType("json");

res.attachment()

Sets the Content-Disposition response header to "attachment" . Optionally, a file name can be passed.

res.attachment("path/to/my/image.png");

res.sendfile(path[, options[, callback]])

Used in res.download() to transfer an arbitrary file.

res.sendfile("path/to/my.file");

This method takes an optional callback parameter, which is called if the file transfer fails or succeeds. By default, next(err) is called, but if callback is passed, then this must be done explicitly, or handle the error.

res.sendfile(path, function(err) ( if (err) ( next(err); ) else ( console.log("transferred %s", path); ) ));

You can also pass options to the fs.createReadStream() call. For example, to change the buffer size:

res.sendfile(path, ( bufferSize: 1024 ), function(err) ( // processing... ));

res.download(file[, filename[, callback[, callback2]]])

Upload this file as an attachment (you can specify an optional alternative file name).

res.download('path/to/image.png');

res.download('path/to/image.png', 'foo.png');

This is equivalent to the following:

res.attachment(file); res.sendfile(file);

Optionally, you can specify a callback as the second or third argument to res.sendfile() . Within it, you can respond as if the header had not yet been sent.

res.download(path, "expenses.doc", function(err) ( // processing... ));

You can also optionally pass a second callback - callback2 . It handles connection-related errors. However, it should not attempt to send a response.

res.download(path, function(err) ( // error or termination), function(err) ( // connection error ));

res.send(body|status[, headers|status[, status]])

The res.send() method is a high-level response facility that allows you to pass objects (for a JSON response), strings (for an HTML response), Buffer instances, or integers specifying a status code (404, 500, etc.) . Here's how it's used:

res.send(); // 204 res.send(new Buffer("wahoo")); res.send(( some: "json" )); res.send(""); res.send("Sorry, can't find that", 404); res.send("text", ( "Content-Type": "text/plain" ), 201); res.send(404);

By default, the Content-Type header is set automatically. However, if it was manually set explicitly in res.send() or before using res.header() , or using res.contentType() , then it will not be automatically set.

Note that this method ends the response (similar to res.end()), so if you need to produce multiple responses, or a stream, you need to use res.write() .

res.json(obj[, headers|status[, status]])

Sends a JSON response with optional headers and status code. This method is ideal for organizing a JSON API, but JSON can also be sent using res.send(obj) (which is not ideal if you only want to send a JSON encoded string, since res.send(string) will send HTML)

res.json(null); res.json(( user: "tj" )); res.json("guard!", 500); res.json("Nothing found", 404);

res.redirect(url[, status])

Redirects to the specified URL. The default status code is 302.

res.redirect("/", 301); res.redirect("/account"); res.redirect("http://google.com"); res.redirect("home"); res.redirect("back");

Express supports shortcuts for redirects - the default ones are "back" and "home" . In this case, "back" redirects to the URL specified in the Referrer (or Referer) header, and "home" uses the "home" setting (default "/").

res.cookie(name, val[, options])

Sets the value of the cookie named name to val . Options: httpOnly, secure, expires, etc. The path option defaults to the value set in the "home" setting, usually "/" .

// "Remember me" for 15 minutes res.cookie("rememberme", "yes", ( expires: new Date(Date.now() + 900000), httpOnly: true ));

The maxAge property can be set to expire relative to Date.now() in milliseconds. So our above example can now be rewritten as:

res.cookie("rememberme", "yes", ( maxAge: 900000 ));

To parse incoming cookies, use the cookieParser layer, which generates a req.cookies object:

app.use(express.cookieParser()); app.get("/", function(req, res) ( // use req.cookies.rememberme ));

res.clearCookie(name[, options])

We clear the cookie named name , assigning the expires parameter a date in the distant past. The options are the same as for res.cookie() , path also defaults to the "home" setting.

res.clearCookie("rememberme");

res.render(view[, options[, fn]])

Renders a view with the given options and an optional fn callback. When fn is given, the response to the client is not automatic, otherwise a text/html response is made with code 200 .

The options passed are also local view variables. For example, if we want to pass the user variable and disable the layout, we do it in one object:

var user = ( name: "tj" ); res.render("index", ( layout: false, user: user ));

The options object is also used to pass options. For example, if you pass the status property, not only does it become available to the view, but it also sets the status code of the response. This is also useful if the template engine accepts certain options, such as debug or compress . Below is an example of how you can render an error page - status is passed here both to display it and to set the status code res.statusCode .

res.render("error", ( status: 500, message: "Internal Server Error" ));

res.partial(view[, options])

Renders a fragment with the given options. This method is always accessible from the view as a local variable.

  • object - the object passed to the view
  • as is the name of the variable that will represent the object object or each element of the collection passed to the view. Default is the name of the view.
    • as: "something" - will add a local variable something
    • as: this - will use the collection element as the view context (this)
    • as: global - merges the properties of the collection element and local view variables
    • collection - an array of objects. Its name comes from the name of the view. For example video.html will have a video object inside.

The following constructs are equivalent to each other and the collection name passed to the fragment will always be "movie" .

partial("theatre/movie.jade", (collection: movies )); partial("theatre/movie.jade", movies); partial("movie.jade", (collection: movies )); partial("movie.jade", movies); partial("movie", movies); // Inside the view: moovie.director

To change the name of a local variable from "movie" to "video" you can use the as option:

partial("movie", (collection: movies, as: "video" )); // Inside the view: video.director

We can also make movie the this value inside our view so that instead of movie.director we can refer to this.director .

partial("movie", (collection: movies, as: this )); // Inside the view: this.director

An alternative solution is to expand the properties of a collection element into pseudo-global (actually local) variables using as: global , which is syntactic sugar:

partial("movie", (collection: movies, as: global )); // Inside the view: director

The same logic applies not only to collections, but also to an object inside a fragment view:

partial("movie", ( object: movie, as: this )); // Inside the view: this.director partial("movie", ( object: movie, as: global )); // Inside the view: director partial("movie", ( object: movie, as: "video" )); // Inside the view: video.director partial("movie", ( object: movie )); // movie.director

When the second argument is a non-collection (without .length), it is treated as an object. In this case, the name of the local variable for this object is formed from the name of the view.

var movie = new Movie("Nightmare Before Christmas", "Tim Burton") partial("movie", movie) // => Inside the view: movie.director

The exception to this rule is when a simple object ("()" or "new Object") is passed in, then it is considered a local object and is not accessible by name within a fragment view. For example, in the following example you would expect there to be a local variable "movie" , however since this is a simple object, the local variables are already "director" and "title" , that is, its properties:

var movie = ( title: "Nightmare Before Christmas", director: "Tim Burton" ); partial("movie", movie)

For such cases, when you need to pass a simple object, simply assign it to some property, or use the object property, which will inherit the object name from the file name. The examples listed below are equivalent:

partial("movie", ( locals: ( movie: movie )) partial("movie", ( movie: movie )) partial("movie", ( object: movie ))

The same API can be used from a route so that you can respond with an HTML fragment via AJAX or WebSockets, for example you can render a collection of users directly from the route:

app.get("/users", function(req, res) ( if (req.xhr) ( // send in response each user from the collection // passed to the view "user" res.partial("user", users) ; ) else ( // respond with a full layout with a user list page // the template of which makes partial("user", users) // and adds some kind of interface res.render("users", ( users: users ) ); ) ));

res.local(name[, val])

Get or set the specified local variable. Local variables in this case refer to variables passed to the view's rendering methods, such as res.render() .

app.all("/movie/:id", function(req, res, next) ( Movie.get(req.params.id, function(err, movie) ( // Makes the assignment res.locals.movie = movie res .local("movie", movie )); app.get("/movie/:id", function(req, res) ( // local variable movie already exists // but we can add it if needed res.render("movie", ( displayReviews: true ) ); ));

res.locals(obj)

Assign multiple local variables using the given obj object. The following is equivalent:

res.local("foo", bar); res.local("bar", baz); res.locals(( foo: bar, bar, baz ));

Server

app.set(name[, val])

Set the application name setting to val , or get the value of the name setting if val is missing:

app.set("views", __dirname + "/views"); app.set("views"); // => ...path...

You can also get to the settings via appsettings:

app.settings.views // => ...path...

app.enable(name)

Sets the name setting to true:

app.enable("some arbitrary setting"); app.set("some arbitrary setting"); // => true app.enabled("some arbitrary setting"); // => true

app.enabled(name)

Checks if the name setting is true:

app.enabled("view cache"); // => false app.enable("view cache"); app.enabled("view cache"); // => true

app.disable(name)

Set the name setting to false:

app.disable("some setting"); app.set("some setting"); // => false app.disabled("some setting"); // => false

app.disabled(name)

Checks if the name setting is false:

app.enable("view cache"); app.disabled("view cache"); // => false app.disable("view cache"); app.disabled("view cache"); // => true

app.configure(env|function[, function])

Specifies the callback function callback for the env environment (or for all environments):

app.configure(function() ( // runs for all environments )); app.configure("development", function() ( // only executed for the "development" environment));

app.redirect(name, val)

For res.redirect() we can define shortcuts (in application scope) as below:

app.redirect("google", "http://google.com");

Now in the route we can call:

res.redirect("google");

You can also do dynamic abbreviations:

app.redirect("comments", function(req, res) ( return "/post/" + req.params.id + "/comments"; ));

Now you can do the following and the redirect will be dynamically built in accordance with the request context. If we called the route with GET /post/12, our redirect will be /post/12/comments.

app.get("/post/:id", function(req, res) ( res.redirect("comments"); ));

In case of a mounted application, res.redirect() will take into account the application's mount point. For example, if the blog application is mounted at /blog , the following example will redirect to /blog/posts:

res.redirect("/posts");

app.error(function)

Adds an error handler function whose first parameter will accept all exceptions, as shown below. Note that it is possible to set multiple error handlers by calling this method multiple times, however the method must call next() if it does not want to handle the exception itself:

app.error(function(err, req, res, next) ( res.send(err.message, 500); ));

app.helpers(obj)

Registers static view helpers.

app.helpers(( name: function(first, last) ( return first + ", " + last ), firstName: "tj", lastName: "holowaychuk" ));

Our view can now use the firstName and lastName variables and the name() function.

<%= name(firstName, lastName) %>

Express also provides several local variables by default:

  • settings - application settings object
  • layout(path) specify the layout directly from inside the view

This method is aliased app.locals() .

app.dynamicHelpers(obj) (#app.dynamic-helpers)

Registers dynamic view helpers. Dynamic view helpers are simply functions that take res , req and are executed in the context of the Server instance before rendering any view. The return value of such a function becomes a local variable with which the function is associated.

app.dynamicHelpers(( session: function(req, res) ( return req.session; ) ));

Now all our views will have access to the session - the session data will be available in the manner of session.name, etc.:

<%= session.name %>

app.lookup

Returns the route handlers associated with the given path .

Let's say there are these routes:

You can use the lookup functionality to check which routes are specified. This may be useful for higher level frameworks built on Express.

app.lookup.get("/user/:id"); // => app.lookup.get("/user/:id/:op?"); // => app.lookup.put("/user/:id"); // => app.lookup.all("/user/:id"); // => app.lookup.all("/hey"); // =>

The alias for app.lookup.HTTP_METHOD() is simply app.HTTP_METHOD() - without the callback argument. This is the reduction. For example the following is equivalent:

app.lookup.get("/user"); app.get("/user");

Each returned function is supplemented with useful properties:

var fn = app.get("/user/:id/:op?"); fn.regexp // => /^\/user\/(?:([^\/]+?))(?:\/([^\/]+?))?\/?$/i fn .keys // => ["id", "op"] fn.path // => "/user/:id/:op?" fn.method // => "GET"

app.match

Returns an array of callback functions that fire on the given URL, which may contain a query string, etc. This can be useful to understand which routes have the ability to respond.

Let's say we have the following routes:

app.get("/user/:id", function() ()); app.put("/user/:id", function() ()); app.get("/user/:id/:op?", function() ());

Calling match on GET will return two functions because the :op in the last route is an optional parameter.

app.match.get("/user/1"); // =>

And the next call will only return one callback for /user/:id/:op? .

app.match.get("/user/23/edit"); // =>

We can also use all() if the HTTP method is not important to us

app.match.all("/user/20"); // =>

Each function is equipped with the following properties:

var fn = app.match.get("/user/23/edit"); fn.keys // => ["id", "op"] fn.params // => ( id: "23", op: "edit" ) fn.method // => "GET"

app.mounted(fn)

Assign a callback to fn that is called when this Server is passed to Server.use() .

var app = express.createServer(), blog = express.createServer(); blog.mounted(function(parent) ( //parent is app // this is blog )); app.use(blog);

app.register(ext, exports)

Associates the specified export properties (exports) of the template engine with the ext extension of the template file.

app.register(".html", require("jade"));

This can also be useful in the case of libraries whose name does not exactly match the template file extension. Living example - Haml.js, which is installed npm-om as "hamljs" and we can register it with ".haml" templates rather than ".hamljs" as would be the default:

app.register(".haml", require("haml-js"));

In addition, app.register is very helpful in the case of template engines whose API does not comply with the Express specifications. In the example below we associate the .md extension with the renderer markdown-files. We will render in HTML only the first time - for better performance - and we will support variable substitution of the form "(name)".

app.register(".md", ( compile: function(str, options) ( var html = md.toHTML(str); return function(locals) ( return html.replace(/\(([^)]+) \)/g, function(_, name) ( return locals; ) ));

app.listen()

We bind the app server socket to the host:port address. The default port is 3000, the host is INADDR_ANY.

app.listen(); app.listen(3000); app.listen(3000, "n.n.n.n");

The port argument can also be a string representing the path to unix domain socket:

app.listen("/tmp/express.sock");

Now let's try:

$ telnet /tmp/express.sock GET / HTTP/1.1 HTTP/1.1 200 OK Content-Type: text/plain Content-Length: 11 Hello World

Project participants

The main contributors to the project were the following:

  • TJ Holowaychuk (visionmedia)
  • Ciaran Jessup (ciaranj)
  • Aaron Heckmann (aheckmann)
  • Guillermo Rauch (guille)

Third party modules

The following modules work with or are built on top of Express:

  • provides resource routing
  • express-messages rendering popup notifications
  • express-configure support for asynchronous configuration (loading data from Redis, etc.)
  • express-namespace - namespaces in routes
  • express-expose simply publishes JS code to the client side of the application
  • express-params - app.param() extensions
  • express-mongoose - plugin for easily rendering results of Mongoose queries (ORM for MongoDB)

Basics of Node JS & Express (III).

Let's understand what npm is and what it is needed for. Install Express and EJS template engine. We do all the preparatory work and start creating our own website in NodeJS.

Now with parameters that will constantly change.

If we need to create a reference to a certain value, after /mews/value . It will change. For example: 23, part or any other value.

App.get("/news/:id", function(req, res)( res.send("ID is - " + req.params.id); ));

Depending on this parameter, we can take data from the database (database) and display a specific article.

We need a certain html file where we will transfer the data of our id and, depending on this data, display this or that information.

We need some template engine.

Thanks to Express, we can use multiple template engines.

Since EJS is an optional package, we need to install it.

Press Enter

After that it will be installed in our project.

It allows you to pass data to various templates, and these templates will have a .ejs extension.

In these templates we will be able to display our html code along with the js code inserted into it (variables, output loops and much more).

There will be a page template that will change depending on the data transferred to it.

The first thing we need to do is specify which view engine we will use.

View engine is essentially a template engine.

Since there are a huge number of them, and we chose EJS, we must indicate it in our index.js file.

Immediately after initializing the app variable.

App.set("view-engine", "ejs");

All files that we will display will be searched in the views folder by default.

At the same level where index.js we will create a views folder.

In it we will create a new file news.ejs. This will be a kind of template that we will fill out.

We can place the most common html code in these templates.

News

News page.

To do this, I don't need to use the .send or .sendFile method, but I will need the render() method.

The render() method takes the desired file (template) in the views folder and can display it in the browser. Plus, it can pass certain parameters to this template.

The extension may not be specified in the render() method. Next, you can pass some parameters to the template itself. Therefore, we pass the object as the second parameter. It can contain a large number of properties and values.

Let's say that we decided to pass a certain parameter newsId with the value req.params.id - that is, the value will be the called id itself.

App.get("/news/:id", function(req, res)( render("news", (newsId: req.params.id)); ));

Thus, a value will be passed to the news template, which will be called newsId with the value id .

We can accept and display all this in the news.ejs file.

Let's change our news.ejs file a little. We will display the ID in the page title.

Everything can be found in the documentation for the EJS template engine (link above).

News page with ID =<%= newsId %>

File /views/news.ejs

News

News page with ID =<%= newsId %>

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eaque numquam libero, veniam ipsum similique odit molestiae esse quia blanditiis magni debitis aliquam, pariatur nam quaerat quas nemo, facilis temporibus laboriosam. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Maiores enim vitae dolore nemo quas aliquam quia corrupti rerum ipsam ad nesciunt, architecto, pariatur officiis. Maxime iste ullam quibusdam, nobis voluptas!

index.js file

Let express = require("express"); let app = express(); app.set("view engine", "ejs"); app.get("/", function(req, res)( res.sendFile(__dirname + "/index.html"); )); app.get("/about", function(req, res)( res.sendFile(__dirname + "/about.html"); )); app.get("/news/:id", function(req, res)( res.render("news", (newsId: req.params.id)); )); app.listen(8080);

We can pass multiple parameters. For example:

App.get("/news/:id", function(req, res)( res.render("news", (newsId: req.params.id, newParam: 535 )); ));

And in the news.ejs file we will display it on the page, for example like this:

<%= newParam %>

In addition, we can transfer our own objects. For example, let's create an object:

App.get("/news/:id", function(req, res)( let obj = (title:"News", id: 4); res.render("news", (newsId: req.params.id, newParam: 535)); ));

And we can also transfer this object. First, we determine the name of what we will transmit, and then we indicate what we are transmitting.

For example:

App.get("/news/:id", function(req, res)( let obj = ( title:"News", id: 4); res.render("news", (newsId: req.params.id , newParam: 535, obj: obj ));

Title =<%= obj.title %>

ID=<%= obj.id %>

<%= newParam %>

Passing an array to the template.

Let's create a data array and display it using a loop.

App.get("/news/:id", function(req, res)( let obj = ( title:"News", id: 4, paragraphs:["Paragraph", "Plain text", "Numbers: 3, 7, 24", 476]); res.render("news", (newsId: req.params.id, newParam: 535, obj: obj)); ));

Now in the template itself we will simply output this array in a loop:

    <% obj.paragraphs.forEach(function(item) { %>
  • <%= item %>
  • <% }); %>

Static files and middleware.

Files that can be included in other files.

Now we have one template - news.ejs, but imagine. that there are many of them. Dozens. And you will need to make changes to some part of the code that appears in all these files. A lot of changes will have to be made.

To avoid this, you can use files that can be included in other files. For example. There is a file with the site header. And if you need to change something, then it is enough to make changes to only one file, since it simply connects to others.

In the views templates folder, create a folder called blocks, and in it the file hrader.ejs.

File hrader.ejs

  • To main
  • About us
  • News

Now we need to include this file in all templates. Go to the news file and immediately after the opening body tag write:

<% include blocks/header.ejs %>

The path is specified from the views folder, since the template engine always starts searching there.

Static files.

Let's create a new folder at the index.js level called public. It will contain all static files. These are css files, pictures, documents, etc. All those files. which will be called from various pages of our site.

In this folder we will create another folder - css and in it we will create a file style.css.

We will transfer all the style code from the index.ejs file into it

In the .ejs files we include the styles:

If you check now, nothing will happen. Styles will not connect.

To include static files we need to use middleware:

In the index.js file at the top, just after app.set , we should write:

App.use("/public",);

And now, if we use a link somewhere starting with /public, NodeJS and Express itself will understand what we are using static files and everything will connect correctly.

The second is where we look for them express.static("public") i.e. in the /public folder.

To summarize, in the code app.use("/public", express.static("public")); we track the link that we write in

If it were like this:

Then in this code it would be:

App.use("/assets", express.static("public"));

In this case, public points to a folder!

If you leave it like that, no changes will happen. The file will be included because we will be tracking the assets link.

App.use("/assets ", express.static("public "));

In order to avoid confusion, they usually make the link and folder of the same name. Most often this is public.

Middleware is what we do before we send any data to the page (server).

In this case, this is our middleware.

Creating an HTML Form and Retrieving Data

The first thing we will do is add the form itself to our website.

Open the about.ejs file and here we will add a form using bootstrap technology.

Enter Forms into the search window and copy the first form from the top on the found page.

Let's save and run.

POST request.

Since we will be performing a POST request, we need to add several attributes to the form.

Method="post" - because POST request

And action="" is where you need to redirect the user after he clicks "Submit". In our case it is:

We need to do everything else in the index.js file

First of all, we need to download a package called body-parser.

It allows us to take a POST request that comes from a form and process it. In other words, get all the data from the form.

To install, write in the project folder in the CS.

npm install body-parser

Press - Enter.

The package is installed.

After installation, you should follow simple instructions.

Let's go to the Examples section on the website and find the Express route-specific section there

  1. We connect the modules we need.
  2. Var bodyParser = require("body-parser")

    Var urlencodedParser = bodyParser.urlencoded(( extended: false ))

    That is, the parser that will allow us to take data from a POST request and work with it as we need.

  3. Further, based on the documentation, we see that we need to track the POST request and pass some middleware (urlencodedParser) to it. We've already tracked GET requests before.

We will output the data received from the form to the console.

Console.log(req.body);

You can immediately add a check. If no form data is submitted, we will simply issue an error.

If (!req.body) return res.sendStatus(400)

In the form itself, you need to specify the name attribute for the fields. These will be the names of the properties, and the value will be what the user enters.

About Us. <% include blocks/header.ejs %>

Second level heading.

To main

third level title.

The significance of these problems is so obvious that consultation with a wide range of activists allows us to carry out important tasks in developing systems of mass participation. Ideological considerations of a higher order, as well as the scope and place of personnel training, allow us to assess the importance of the personnel training system that meets pressing needs. It should not be forgotten, however, that consultation with a wide range of assets contributes to the preparation and implementation of a personnel training system that meets urgent needs.

It should not be forgotten, however, that consultation with a wide range of assets contributes to the preparation and implementation of a personnel training system that meets urgent needs.

We"ll never share your email with anyone else.

Let express = require("express"); var bodyParser = require("body-parser"); let app = express(); var urlencodedParser = bodyParser.urlencoded(( extended: false )); app.set("view engine", "ejs"); app.use("/public", express.static("public")); app.get("/", function(req, res)( res.render("index"); )); app.get("/about", function(req, res)( res.render("about"); )); app.post("/about", urlencodedParser, function(req, res)( if (!req.body) return res.sendStatus(400); console.log(req.body); res.render("about") ; )); app.get("/news", function(req, res) ( res.render("news-common",(newParam1:"Param-1")); )); app.get("/news/:id", function(req, res)( let obj = ( title:"News", id: 4, paragraphs:["Paragraph", "Plain text", "Numbers: 3, 7, 24", 476]); res.render("news", (newsId: req.params.id, newParam: 535, obj: obj)); )); app.listen(8080);

Enter the data and click send. In the console we will see the output of this data (property - value).

The page will reload after submitting the form and in the console we will see the data that was sent.

Now we can make it so that after sending we show other data.

Let's change a little code in the index.js file

App.post("/about", urlencodedParser, function(req, res)( if (!req.body) return res.sendStatus(400); console.log(req.body); res.render(" about-success", (data: req.body)); });

This way we will output the about-success.ejs page and we will now create it in the views folder. As the second parameter we will pass the form data as an object. - (data: req.body)

About Us. <% include blocks/header.ejs %>

Hello, It is my first page on Node.js

Second level heading.

To main

Likewise, the strengthening and development of the structure contributes to the preparation and implementation of a personnel training system that meets urgent needs. Likewise, the beginning of the daily work of forming a position requires us to analyze significant financial and administrative conditions.

Thank you

Email: <%= data.email %>
Pass: <%= data.pass %>
isCheck: <%= data.check %>

This way you can track the data that comes from the forms, check them for compliance and if the user has not filled out something, then issue an error, etc.

In addition, it would be convenient to send this data by email or save it in a database.

If you want to send them by mail. then there is another package in npm - Nodemailer. This package allows you to send data directly to email. It's easy to use. And with the help of it you can receive by mail all the data of the form filled out by the user.

NodeJS provides us with many additional packages. For example, we used Express to make it easier to track links and use template engines. Body-parseer in order to accept data received from the form. Nodemailer - for sending data by email.

How to get data from a URL string.

Sometimes you need to get this type of data from the address bar:

http://localhost:8080/news/12?filter-id&city=london

Let's look at how to get this data using this code from the index.js file as an example:

App.get("/news/:id", function(req, res)( let obj = ( title:"News", id: 4, paragraphs:["Paragraph", "Plain text", "Numbers: 3, 7, 24", 476]); res.render("news", (newsId: req.params.id, newParam: 535, obj: obj)); ));

Let's simply output this data to the console:

App.get("/news/:id", function(req, res)( let obj = ( title:"News", id: 4, paragraphs:["Paragraph", "Plain text", "Numbers: 3, 7, 24", 476]); console.log(req.query); res.render("news", (newsId: req.params.id, newParam: 535, obj: obj)); ));

In the console we will see

( filter: "id", city: "london")

This can be useful sometimes.

As you can see from the title, our article will focus on choosing one of three frameworks for Node.js: Express, Koa And Sails.

At the end of the article we will share with you the choice of companyand we will explain why the framework we have chosen should be given special attention.

Let us immediately emphasize that the task is quite complex, and it will be difficult to proclaim one of the options as optimal and suitable for all occasions.

In our article, we will first describe the main characteristics of each framework. And once you have a general impression of them, let's compare the three frameworks based on a few key criteria.

Now let's move to2009, when two-year experimentsRyan Dahlto create server-side web components were successful and a fundamentally new technology appeared.

Node.js an event-driven platform used for creating web applications that provides the ability to use JavaScript on the server side.

Since before the advent of Node.js, JavaScript was used only on the client side, the emergence of such a platform was greeted with enthusiasm by developers. Essentially, this opened up new possibilities for creating applications with high performance and scalability.

It must be admitted that the developers’ expectations were met, and at the moment Node.js remains popular and continues to move forward.

To verify this, it is enough to track the frequency of release updates and scope of changes made .

The Node.js community is growing and evolving. New ideas are generated regularly, resulting in new tools and libraries.

Thanks to this pace of development, developers have a wide range of frameworks at their disposal, and such diversity, as a rule, involves difficult choices.

In his Then we will choose one of three MVC frameworks,which are used for the server part (backend) of applications on Node.js.

MVC (Model-View-Controller) a design pattern that includes three components: Model, View, and Controller. All three components can be changed independently of each other. In this case, the model provides the data and control logic rules, the view is responsible for displaying the data on the user interface, and the controller provides interaction between the model and the view.

For comparison within the framework of this article, m you have chosen:

  • Express, as the most flexible, simple and fastest framework
  • Koa as a version Expressnew generation, created by the same development team
  • Sails , as designed for rapid application development based on the principlesRuby on Rails And Express.

Each of these frameworks has its followers and opponents, who can endlessly argue with each other, giving their own reasons for and against.

But at the same time, all three options have certain characteristics and features that provide an advantage in a particular situation. ations.

EXPRESS.JS

Let's start the description with the simplest framework used on the Node.js platform.

Express has been used for application development for quite a long time and, thanks to its stability, firmly occupies the position of one of the most

There are a large number of detailed instructions and descriptions for this framework, which were compiled by developers who have tested its effectiveness in practice. Therefore, it is withExpressIt is recommended to get started if you intend to learn how to create applications on the Node.js platform.

Agree, it is much wiser to use accumulated and proven experience than to reinvent the wheel.

The main feature of this framework is that forExpress characteristic small amount of basic functionality. All other functions you need will need to be obtained through external modules. In fact,Expressin its pure form, it is a server and may not have a single module.

Thanks to this minimalism, the developer initially has at his disposaleasy and quick toolwhich he can expand and develop.

It is important that the choice of modules forExpressis not associated with any restrictions: neither quantitative nor functional.

As a result, this framework provides the developer with the opportunity to solve any problem without limiting him in the choice of tools.

On the one hand, one cannot but rejoice at the fact that the lack of ready-made universal solutions actually means that everythe application you create will be unique.

On the other hand, the developer needs to independently select and organize modules, and this involves a large amount of work and, accordingly, requires more time and effort from the developer.

PROS:

✓ simplicity

✓ flexibility

✓ good scalability

✓ developed community

✓ detailed documentation

✓ wide selection of plug-ins

MINUSES:

✗ large amount of manual work

✗ an outdated approach is used callbacks functions

KOA.JS

Koawas created by a team of developers likeframework optionExpress in the new generation. This enhanced version is designed to help you create web applications and APIs with improved performance. Accordingly, the creators sought to take into account all the shortcomings of its predecessor and make it more modern and easy to use.

Let's see how successful this was.

Koahas almost the same functionality and is superiorExpress by ease.

A distinctive feature of Koa is the use of ES6 generators.

Generators – a type of function that can be started, stopped, and resumed regardless of what stage of execution it is in, and still retain its content.

Application of ES6 generators inKoaallows you to eliminate callbacks callbacks ), reduces the amount of code work for developers and reduces the likelihood of errors.

Thanks to the fact that the creatorsKoathe disadvantages identified in the process of working withExpress, this framework boasts that its applicationsignificantly simplifies adaptation to specific customer requests (customization). And such a characteristic can ultimately play a decisive role in the selection process: today, in a highly competitive environment, any application tends to use its own style.

If we talk about disadvantages, they are mainly associated with relative youthKoa(appeared in 2013). The framework does not enjoy the support of such a large community asExpress, and has not yet had time to demonstrate all its capabilities.

PROS:

✓ lightweight

✓ flexible

✓ fast

✓ ES6 generators

✓ better customization

MINUSES:

✗ insufficient community support

SAILS.JS

This framework is designed ascomplete finished product, which already includes enough functionality to get you started, and at the same time uses a minimum number of external modules.

Accordingly, such a framework will initially beheavier than the previous two.

On the one hand, a minimum amount of effort is required from the developer, since the framework’s own functionality is used to create the application. There is no need to delve into the intricacies of the process - you can simply take a ready-made, proven solution.

On the other hand, application development will be limited by the framework tools available, since external modules forSailsmuch less than forExpress or Koa.

A distinctive feature of the framework is the built-in programming technologyWaterline ORM (English Object-Relational Mapping), which is used to provide communication with various databases.

The presence of such a component could be considered an advantage, but in the process of work you may encounter certain limitations. For example,Waterlinedoes not support transactions, new features and bug fixes are introduced untimely.

In general, slower development was characteristic of the entire community until recentlySails, especially compared to others supporting the ones described aboveExpress And Koa. But it should be noted that at the moment the Sails community has begun to gain momentum and develop more actively.

PROS:

✓ rich functionality

✓ Socket.io support

✓ documentation in one place

✓ it’s easier to find a specialist with experience in Sails

MINUSES:

✗ heavy

✗ slow

✗ Waterline restrictions

✗ insufficiently detailed documentation

We have described the main properties characteristic of the three frameworks, which are quite sufficient to form an objective impression about them.

If you have any questions, contact us right now!

To help you more clearly compare the three frameworks based on the features mentioned above, the companyoffers a smallcomparison table.

Let's try to dogeneral conclusionfrom what we already know about the three frameworks under consideration. Let's determine for which projects, in general, each of them is better suited:

Express.js suitable for:

  • novice programmers who are focused on professional growth in Node JS;
  • large projects involving customization;
  • cases where long-term application support is required.

Sails.js suitable for:

  • quick start of the project;
  • fast startups that do not expect to expand in the future;
  • real-time applications where instant response is required;
  • beginner Node.js programmers;
  • applications that do not require long-term support.

To be fair, we note that real-time applications can also be created using Express. However, when developing such an application using Sails, it will take much less time and effort to create and configure.

Koa.js suitable for:

  • both small and large projects that involve future development;
  • for projects with a high degree of customization;
  • to facilitate long-term application support.

Now that we have looked in detail at the pros and cons of each of the three frameworks, let's talk about which framework we choose and why.

We choose Koa because:

  • Like Express, Koa does not restrict the developer from using built-in modules, but gives the opportunity to choose from setsexactly the one that is best suited for a specific project;
  • Koa incorporates the strengths of the proven and widely used Express framework;
  • the creators of Koa had the opportunity to analyze the difficulties faced by developers using Express;
  • when creating Koa, the shortcomings of its predecessor were taken into account;
  • Koa is based on new standards and follows modern trends;
  • Koa is suitable for developing a wide variety of applications of any size, with any degree of customization and with any support requirements;

... and the most important argument – this is the specialists’ own positive experience, acquired while working with this framework.

In any case, approach the decision from a rational point of view and give preference to the framework that is equipped according to your specific requirements.

We are always ready to support your choice and help you implement any project. Don't put it off until tomorrow and right now!

This article is intended for beginner developers and anyone interested in working with Node js Express. To master this you must know the basics of JavaScript:

What is Node.js?

Node.js is an asynchronous JavaScript runtime based on Chrome's V8 JavaScript engine. It is designed for creating scalable network applications.

Node.js allows you to write server-side JavaScript code. Now you may be wondering how? JavaScript is a language that runs in the browser. The browser accepts JavaScript code and compiles it into commands. The creator of Node.js took the Chrome engine and built a runtime ( runtime) so that it works on the server. It is the medium in which language can be interpreted. So what do we have now? A way to write JavaScript in the backend.

As for the definition, you might be wondering what the term "asynchronous" means in this context. JavaScript is a single threaded language. Therefore, you don't want events to interrupt the main thread of execution. This means processing events without interrupting the main thread.

Node.js is based on this non-blocking design, making it one of the fastest tools for building web applications. In the following "Hello World" example, many connections can be processed simultaneously. Each connection triggers a callback.

This Node js Express example has six simple steps.

  1. Install Node.js for your platform (MacOS, Windows or Linux)

Node.js

Node.js® is a JavaScript runtime built into the V8 JavaScript engine for Chrome. Node.js uses event-driven, non-blocking I/O...

The first step is to get an instance of JavaScript on your local machine. Type nodejs.org into your browser's address bar or click on the link, and you're done. The launch window should give you what you want right away. When I launch Ubuntu on my computer, the corresponding version of Node.js for my operating system is displayed. Download and install it. This will provide you with the tools you need to run the server on your local computer:

  1. Open a command prompt and type

mkdir myapp cd myapp

These Node js Express Post commands are universal for any operating system. The first will create a new directory inside the directory you are currently in, mkdir = "make directory" . The latter will change to this newly created directory, cd = "change directory" .

  1. Run your project and link it to npm

After creating a directory called myapp, you will need to run the project and link it with npm.

Npm is short for node package manager ( Node package manager). This is where all Node packages are located. They can be thought of as packages of code, modules that perform a specific function. We use the application program interface, API, provided by these modules.

The modules, in turn, act as black boxes with buttons and levers that can be pushed and pulled to achieve the desired result. Running the command below starts your project:

It creates a package.json file in the myapp folder. The file contains links to all npm packages that are loaded into the project.

The command will prompt you to enter several options for action. You can enter your path through all of them except this one:

entry point: (index.js)

You'll want to change this to:

  1. Install Express in myapp directory

Express is a minimal and flexible Node.js web application framework that provides a robust set of features for the web.

While in the myapp directory, run:

npm install express --save

The installation command will continue searching for the Node js Express files package to install. Install it in your project.

Now a node_modules folder is created in the root of your project. Adding -save allows the package to be saved to the dependency list located in package.json in the myapp directory.

Express provides a set of tools for creating and running a web application. Express has become so popular that it is now standard in the vast majority of Node.js applications. I highly recommend using Express.

  1. Launch a text editor and create a file called app.js

After installing Express Node, add the following code to the created file:

var express = require("express"); var app = express(); app.get("/", function (req, res) ( res.send("Hello World!"); )); app.listen(3000, function () ( console.log("Example app listening on port 3000!"); ));

Here you will need to use a package that was recently installed. The first line declares a variable that will contain the express module, located in the node_modules folder.

A module is a function. Assigning a function call to another variable provides access to a predefined set of tools that make future work easier. You can think of a temporary application as an object whose methods you use to create the actual program.

The listen method starts the server and listens on port 3000 for connections. He replies “Hello World! " for GET requests to the root URL (/). For any other path it will respond with 404 Not Found.

  1. Launch the application

Enter the command:

After running the command, enter http://localhost:3000/ in your browser to see the result. You should also see " Example app listening on port 3000».

Looking at the syntax pattern, if we wanted to add a new route to the application, we could simply do something like the following:

Router.get("/app", function(req, res) ( res.render("app", ( title: "Express" )); ));

Is this the route? Is this a controller?

The most interesting thing is that a route is a function containing logic. Inside the route is the res.render function:

Res.render("foo", ( title: "Express" ));

In the view template we see this:

H1= title p Welcome to #(title)

These are two examples of how we can pull data from controller/route and display it in a view. In this example we output HTML:

Express

Welcome to Express

This all seems to stem from the problem - can a route also contain controller information? This is true, which is why there is a movement in the community to change the name of the folder from routes to controllers.

A great example of this can be seen in the Express MVC example.

But for the sake of consistency, we will stick to current conventions in this guide.

404 errors

Errors are already sending you to Express. The app.js file has the following:

/// catch 404 and redirect to error handler app.use(function(req, res, next) ( var err = new Error("Not found"); err.status = 404; next(err); ));

There is errors.jade in the views/ folder.

Extends layout block content h1= message h2= error.status pre #(error.stack)

It's simple. If you want to customize your 404 page, then just edit this view.

mob_info