Overview
The webapp
object conventionally denotes the application. The webapp
object has methods for:
- Routing HTTP requests; see for example,
app.METHOD()
. - Configuring middleware; see
app.route()
. - Rendering HTML views; see
app.render()
. - Registering a template engine; see
app.engine()
.
It also has settings (properties) that affect how the application behaves; for more information, see app.set()
.
The application object can be referred from the Request object
and the Response object
as req.app
, and res.app
, respectively.
User can use the following code to import the WebApp
module.
var WebApp = require("webapp");
Support
The following shows WebApp
module APIs available for each permissions.
User Mode | Privilege Mode | |
---|---|---|
WebApp.create | ● | ● |
WebApp.createApp | ● | ● |
WebApp.createSub | ● | ● |
WebApp.Router | ● | ● |
WebApp.static | ● | ● |
app.locals | ● | ● |
app.isMaster | ● | ● |
app.addcert | ● | ● |
app.all | ● | ● |
app.METHOD | ● | ● |
app.groupName | ● | ● |
app.disable | ● | ● |
app.disabled | ● | ● |
app.enable | ● | ● |
app.enabled | ● | ● |
app.engine | ● | ● |
app.render | ● | ● |
app.route | ● | ● |
app.start | ● | ● |
app.stop | ● | ● |
app.port | ● | ● |
app.set | ● | ● |
app.use | ● | ● |
WebApp Class
WebApp.create(group, subs[, taskFile], saddr[, tlsOpt])
group
{String} Server group name(master server module). Usually the module name is used as the group name. If the server work on mult-task mode(subs > 0) andtaskFile
is missing, thegroup
must be supported as app module name.subs
{Integer} Sub task counts, ifsubs > 0
, app run in multi-task mode.taskFile
{String} Sub task module name. default: usegroup
as module name.saddr
{Object} Server socket address. If the port ofsaddr
is set to0
, the server port will be assigned automatically, and that can be get byapp.port()
.tlsOpt
{Object} TLS securely connections options. default: undefined, means use TCP connection.
This method creates a master-server. When the master-server starts, it can create a specified number(subs) of sub-servers (subs), refer to WebApp mult-task
.
Example
- Create single server:
var WebApp = require("webapp");
var socket = require("socket");
var saddr = socket.sockaddr(socket.INADDR_ANY, 8000);
var app = WebApp.create("webapp", 0, saddr);
app.use("/", function(req, res) {
res.send("Hello world.");
});
app.start();
- Create mult-task server:
var WebApp = require("webapp");
var socket = require("socket");
var saddr = socket.sockaddr(socket.INADDR_ANY, 8000);
var app = WebApp.create("./webapp", 2, saddr);
app.use("/", function(req, res) {
res.send(`my ser is: ${app.groupName.name}`);
});
app.start();
WebApp.createApp([subs])
subs
{Integer} the new task counts, ifsubs > 0
, app run in multi-task mode.
This method creates a master-server (name: './__webapp__
'). If developing an EdgerOS application, use this function to create a WebApp
object. When the master-server starts, it can create a specified number(subs) of sub-servers (subs), refer to WebApp mult-task
.
Example
- Create single server:
var WebApp = require("webapp");
var app = WebApp.createApp();
app.use("/", function(req, res) {
res.send("Hello world.");
});
app.start();
- Create mult-task server:
var WebApp = require("webapp");
var app = WebApp.createApp(2);
app.use("/", function(req, res) {
res.send(`my ser is: ${app.groupName.name}`);
});
app.start();
- Sub-server (./__webapp__.js):
var WebApp = require("webapp");
var app = WebApp.createSub("./__webapp__");
app.use("/", function(req, res) {
res.send(`my ser is: ${app.groupName.name}`);
});
app.start();
WebApp.createSub(group)
group
{String} Server group name, the same as master-server group name.
Use this method to create a sub-server when the sub-server is not on the same module as the master-server.
Example
- Master-server:
var WebApp = require("webapp");
var socket = require("socket");
var saddr = socket.sockaddr(socket.INADDR_ANY, 8000);
var app = WebApp.create("web_mult", 2, "./web_mult_sub", saddr);
app.use("/", function(req, res) {
res.send(`my ser is: ${app.groupName.name}`);
});
app.start();
- Sub-server (./web_mult_sub.js):
var WebApp = require("webapp");
var app = WebApp.createSub("web_mult");
app.use("/", function(req, res) {
res.send(`my ser is: ${app.groupName.name}`);
});
app.start();
WebApp.Router([web[, options]])
web
{Object} webapp instance.options
{Object} Options.
This is web router, See webrouter for details.
Example
var Router = WebApp.Router;
var router = Router.create();
app.use(router);
WebApp.static(root[, options])
root
{String} root directory of serve files.options
{Object} Options.
This is serveStatic
middleware, See serveStatic for details.
Example
var static = WebApp.static;
app.use(static("public"));
WebApp mult-task
The WebApp have two work mode:
MASTER
The master-server listens and receives the client request. If the sub server is registered on the master server, the master server will dispatch the request to itself or the sub server for processing.SUB
The sub-server works on a separate task. It does not listen on the port, does not directly accept requests from the client, but accepts requests dispatched by the master-server.
A WebApp can be a single task or multiple tasks(mult-task). When it works in mult-task mode, there is one master-server and several sub-servers, which are created by master-server when the master-server is started. When the master-server is working, the client requests are evenly distributed to all the sub-servers and the master-server itself.
The sub-server can be the same module as the master-server, or it can be a different module. If they are on the same module, you don't need to create a sub-server explicitly. If the sub-server is not on the same module as master-server, user should create it by createSub
.
WebApp Object
app.locals
- {Object} The
app.locals
object has properties that are local variables within the application. Once set, the value ofapp.locals
properties persist throughout the life of the application,
You can access local variables in templates rendered within the application. This is useful for providing helper functions to templates, as well as application-level data. Local variables are available in middleware via req.app.locals
.
Example
app.locals.title = "My App";
app.locals.strftime = require("strftime");
app.locals.email = "me@myapp.com";
console.log(app.locals.title);
console.log(app.locals.email);
app.isMaster()
- Returns: {Boolean} Whether it is the master server.
Get whether the server object is the master server.
app.addcert(opt)
opt
{Object} Tls server option.- Returns: {Boolean} Whether it was added successfully.
opt
includes following items:
name
{String} Server domain name.ca
{String} Optional trusted CA certificates. default: no CA certificates.cert
{String} Server certificate.key
{String} Private key of server certificate.passwd
{String} Private key password. default: no password.
This method adds a SNI (Server Name Indication) certificate to the tls server. SNI is an extension used to improve SSL or TLS for servers. It mainly solves the disadvantage that one server can only use one certificate (one domain name). With the support of the server for virtual hosts, one server can provide services for multiple domain names, so SNI must be supported to meet the demand.
app.start()
- Returns: {Boolean} App start success or not.
Start app server. The app's setting must be done before this operator.
app.stop([stopAll][, cb])
stopAll
{Boolean} always true forMASTER
mode, close all task servers. ForSUB
mode: true - stop all task servers; false - stop this sub server. default: false.cb
{Function} Callback whenstop
event emit.
Stop app server.
app.port()
- Returns: {Integer | Undefined} Server socket port.
When the server starts with the MASTER
module, app.port()
gets the port of the server, otherwise it returns undefined
.
Example
var port = app.port();
console.log(port);
app.METHOD([path, ]handle[, handle..])
path
{String | RegExp | Array} The path for which the request handle function is invoked; can be any of:- A string representing a path. default: '/' (root path)
- A path pattern.
- A regular expression pattern to match paths.
- An array of combinations of any of the above.
handle
{Function} The request handle function.WebApp
supportasync
handle, see Async Handle for details.
Routes an HTTP request, where METHOD is the HTTP method of the request, such as GET, PUT, POST, DELETE and so on, in lowercase. Thus, the actual methods are app.get()
, app.post()
, app.put()
, app.delete() and so on.
WebApp supports the following routing methods corresponding to the HTTP methods of the same names in lowercase:
DELETE, GET, HEAD, POST, PUT
CONNECT, OPTIONS, TRACE
COPY, LOCK, MKCOL, MOVE, PROPFIND, PROPPATCH, SEARCH, UNLOCK, BIND, REBIND, UNBIND, ACL
REPORT, MKACTIVITY, CHECKOUT, MERGE
MSEARCH, NOTIFY
EdgerOS 1.8.5 and later supports methods:
SUBSCRIBE, UNSUBSCRIBE
PATCH, PURGE
MKCALENDAR
LINK, UNLINK
SOURCE
Example
- Path:
// This will match paths starting with /abcd:
app.get("/abcd", function(req, res) {
// User handle.
});
- Path Pattern:
// This will match paths starting with `/abcd` and `/abd`:
app.get("/abc?d", function(req, res) {
// User handle.
});
// This will match paths starting with `/abcd`, `/abbcd`, `/abbbbbcd`, and so on:
app.get("/ab+cd", function(req, res) {
// User handle.
});
// This will match paths starting with `/abcd`, `/abxcd`, `/abFOOcd`, `/abbArcd`, and so on:
app.get("/ab*cd", function(req, res) {
// User handle.
});
// This will match paths starting with `/ad` and `/abcd`:
app.get("/a(bc)?d", function(req, res) {
// User handle.
});
- Regular expression pattern:
// This will match paths starting with `/abc` and `/xyz`:
app.get(/\/abc|\/xyz/, function(req, res) {
// User handle.
});
app.all([path, ]handle[, handle..])
path
{String | RegExp | Array} The path for which the request handle function is invoked; can be any of:- A string representing a path. default: '/' (root path)
- A path pattern.
- A regular expression pattern to match paths.
- An array of combinations of any of the above.
handle
{Function} The request handle function.WebApp
supportasync
handle, see Async Handle for details.
This method is like the standard app.METHOD()
methods, except it matches all HTTP verbs.
Examples
The following callback is executed for requests to /secret
whether using GET
, POST
, PUT
, DELETE
, or any other HTTP request method:
app.all("/secret", function(req, res, next) {
console.log("Accessing the secret section ...");
next(); // pass control to the next handler
});
The app.all()
method is useful for mapping 'global' logic for specific path prefixes or arbitrary matches. For example, if you put the following at the top of all other route definitions, it requires that all routes from that point on require authentication, and automatically load a user. Keep in mind that these callbacks do not have to act as end-points: loadUser
can perform a task, then call next()
to continue matching subsequent routes.
app.all("*", requireAuthentication, loadUser);
Or the equivalent:
app.all("*", requireAuthentication);
app.all("*", loadUser);
Another example is white-listed “global”
functionality. The example is similar to the ones above, but it only restricts paths that start with “/api”
:
app.all("/api/*", requireAuthentication);
app.groupName
groupName
{Object}group
{String} The app grpup name, seeWebApp mult-task
.name
{String} The app server name, seeWebApp mult-task
.
app.disable(name)
name
{String} settingname
.
Sets the Boolean setting name
to false
, where name
is one of the properties from the app settings, see set(name[, value])
. Calling app.set('foo', false)
for a Boolean property is the same as calling app.disable('foo')
.
Example
app.disable("case sensitive routing");
app.get("case sensitive routing");
// => false
app.disabled(name)
name
{String} settingname
.- Returns: {Boolean}
true
if the Boolean settingname
is disabled (false
).
Example
app.disabled("case sensitive routing");
// => true
app.enable("case sensitive routing");
app.disabled("case sensitive routing");
// => false
app.enable(name)
name
{String} settingname
.
Sets the Boolean setting name
to true
, Calling app.set('foo', true)
for a Boolean property is the same as calling app.enable('foo')
.
Example
app.enable("case sensitive routing");
app.get("case sensitive routing");
// => true
app.enabled(name)
name
{String} settingname
.- Returns: {Boolean}
true
if the settingname
is enabled (true
).
Example
app.enabled("case sensitive routing");
// => false
app.enable("case sensitive routing");
app.enabled("case sensitive routing");
// => true
app.engine(ext, callback)
ext
{String} extension name.callback
{Function} the handle function of template engine.
Registers the given template engine callback as ext. app
has registered the ejs
engine by default.
app.set(name[, value])
name
{String} settingname
.value
{any} settingvalue
.- Returns: {any} return value of setting
name
whilevalue
omited.
Assigns setting name
to value
. You may store any value that you want, but certain names can be used to configure the behavior of the server.
Calling app.set('foo', true)
for a Boolean property is the same as calling app.enable('foo')
. Similarly, calling app.set('foo', false)
for a Boolean property is the same as calling app.disable('foo')
.
Retrieve the value of a setting with app.get()
.
Application Settings
The following table lists application settings.
Property | Type | Description | Default |
---|---|---|---|
case sensitive routing | Boolean | Enable case sensitivity. When enabled, "/Foo" and "/foo" are different routes. When disabled, "/Foo" and "/foo" are treated the same. | N/A (undefined) |
strict routing | Boolean | Enable strict routing. When enabled, the router treats "/foo" and "/foo/" as different. Otherwise, the router treats "/foo" and "/foo/" as the same. | N/A (undefined) |
views | String or Array | A directory or an array of directories for the application's views. If an array, the views are looked up in the order they occur in the array. | '/views' |
view cache | Boolean | Enables view template compilation caching. | true |
view engine | String | The default engine extension to use when omitted. | ejs engine. |
Example
app.set("title", "My Site");
app.get("title"); // "My Site"
app.get(name)
name
{String} settingname
.- Returns: {any} return value of setting
name
.
Example
app.get("title");
// => undefined
app.set("title", "My Site");
app.get("title");
// => "My Site"
app.get([path, ]handle[, handle..])
Routes HTTP GET requests to the specified path with the specified callback functions. See app.METHOD().
app.render(name[, options], callback)
name
{String} the given viewname
.options
{Object} local variables for the view.callback
{Function} accepting an error and the rendered template string.
Returns the rendered HTML of a view via the callback
function.It accepts an optional parameter that is an object containing local variables for the view. It is like res.render()
, except it cannot send the rendered view to the client on its own.
Example
app.render("email", function(err, html) {
// ...
});
app.render("email", { name: "Tobi" }, function(err, html) {
// ...
});
app.route([path])
path
{String|RegExp} route path.- A string representing a path. default: '/' (root path)
- A path pattern.
- A regular expression pattern to match paths.
- Returns: {Object} an instance of a
Router
.
Returns an instance of a single route, which you can then use to handle HTTP verbs with optional middleware. Use app.route()
to avoid duplicate route names (and thus typo errors).
Example
app
.route("/events")
.all(function(req, res, next) {
// runs for all HTTP verbs first
// think of it as route specific middleware!
})
.get(function(req, res, next) {
res.json({});
})
.post(function(req, res, next) {
// maybe add a new event...
});
app.use([path, ]handle[, handle..])
path
{String|RegExp | Array} The path for which the middleware function is invoked; can be any of:- A string representing a path. default: '/' (root path)
- A path pattern.
- A regular expression pattern to match paths.
- An array of combinations of any of the above.
handle
{Function | Object} A middleware function or router object.WebApp
supportasync
handle, see Async Handle for details.
Mounts the specified middleware function or functions at the specified path: the middleware function is executed when the base of the requested path matches path
.
A route will match any path that follows its path immediately with a "/"
. For example: app.use('/apple', ...)
will match "/apple"
, "/apple/images"
, "/apple/images/news"
, and so on.
Since path
defaults to "/"
, middleware mounted without a path will be executed for every request to the app.
Example
This middleware function will be executed for every request to the app:
app.use(function(req, res, next) {
console.log("Time: %d", Date.now());
next();
});
Middleware functions are executed sequentially, therefore the order of middleware inclusion is important.
// this middleware will not allow the request to go beyond it
app.use(function(req, res, next) {
res.send("Hello World");
});
// requests will never reach this route
app.get("/", function(req, res) {
res.send("Welcome");
});
Error-handling Middleware
Error-handling middleware always takes four arguments. You must provide four arguments to identify it as an error-handling middleware function. Even if you don’t need to use the next
object, you must specify it to maintain the signature. Otherwise, the next
object will be interpreted as regular middleware and will fail to handle errors. For details about error-handling middleware, see: Error Handling.
Define error-handling middleware functions in the same way as other middleware functions, except with four arguments instead of three, specifically with the signature (err, req, res, next)
:
app.use(function(err, req, res, next) {
console.error(err.stack);
res.status(500).send("Something broke!");
});
Events
start
Emitted when the webapp start done.
stop
Emitted when the webapp stop.
ready
Emitted when the multi-task web server's sub task already.
totalSubs
{Integer} Total number of subtasks.openedSubs
{Integer} Number of open subtasks.
final
Emitted before the webapp final handle call. so 'Angular' or 'Vue' web app can use this event send index.html
file to browser.
Example
app.on("final", function(req, res, status, reason, estack) {
if (status === 404) {
res.sendFile("/public/index.html");
}
if (Array.isArray(estack)) {
console.stack(estack);
}
});
task
arg
{Object} Task arguments.i
{Integer} Subtask index, from1
to sub task count.
Emitted when the webapp create sub task. multi-task web servers need to use ARGUMENT
variables to pass parameters, so users cannot directly use ARGUMENT
variables, but user can process user-defined task parameters through ARGUMENT.arg
.
Example
app.on("task", function(arg, i) {
// arg is object, can pass some arguments to sub task.
// i is task index, from 1 to sub task count.
arg.bar = "foo";
});
// Sub task can use following method get arg
console.log(ARGUMENT.arg.bar);
Error Handling
Error Handling refers to how WebApp
catches and processes errors that occur both synchronously and asynchronously. WebApp
comes with a default error handler so you don’t need to write your own to get started.
Catching Errors
It’s important to ensure that WebApp
catches all errors that occur while running route handlers and middleware.
Errors that occur in synchronous code inside route handlers and middleware require no extra work. If synchronous code throws an error, then WebApp
will catch and process it. For example:
app.get("/", function(req, res) {
throw new Error("BROKEN"); // WebApp will catch this on its own.
});
For errors returned from asynchronous functions invoked by route handlers and middleware, you must pass them to the next()
function, where WebApp
will catch and process them.
If you pass anything to the next()
function, WebApp
regards the current request as being an error and will skip any remaining non-error handling routing and middleware functions.
You must catch errors that occur in asynchronous code invoked by route handlers or middleware and pass them to WebApp
for processing. For example:
app.get("/", function(req, res, next) {
setTimeout(function() {
try {
throw new Error("BROKEN");
} catch (err) {
next(err);
}
}, 100);
});
The above example uses a try...catch
block to catch errors in the asynchronous code and pass them to WebApp
. If the try...catch
block were omitted, WebApp
would not catch the error since it is not part of the synchronous handler code.
Use promises to avoid the overhead of the try..catch
block or when using functions that return promises. For example:
app.get("/", function(req, res, next) {
Promise.resolve()
.then(function() {
throw new Error("BROKEN");
})
.catch(next); // Errors will be passed to WebApp.
});
Since promises automatically catch both synchronous errors and rejected promises, you can simply provide next
as the final catch handler and WebApp
will catch errors, because the catch handler is given the error as the first argument.
Whichever method you use, if you want WebApp
error handlers to be called in and the application to survive, you must ensure that WebApp
receives the error.
The Default Error Handler
WebApp
comes with a built-in error handler that takes care of any errors that might be encountered in the app. This default error-handling middleware function is added at the end of the middleware function stack.
If you pass an error to next()
and you do not handle it in a custom error handler, it will be handled by the built-in error handler; the error message will be written to the client.
If you call next()
with an error after you have started writing the response (for example, if you encounter an error while streaming the response to the client) the WebApp
default error handler closes the connection and fails the request.
So when you add a custom error handler, you must delegate to the default WebApp
error handler, when the headers have already been sent to the client:
function errorHandler(err, req, res, next) {
if (res.headersSent) {
return next(err);
}
res.status(500);
res.render("error", { error: err });
}
Note that the default error handler can get triggered if you call next()
with an error in your code more than once, even if custom error handling middleware is in place.
Writing Error Handlers
Define error-handling middleware functions in the same way as other middleware functions, except error-handling functions have four arguments instead of three: (err, req, res, next)
. For example:
app.use(function(err, req, res, next) {
console.error(err.stack);
res.status(500).send("Something broke!");
});
You define error-handling middleware last, after other app.use()
and routes calls; for example:
var bodyParser = require("middleware").bodyParser;
app.use(bodyParser.urlencoded());
app.use(bodyParser.json());
app.use(function(err, req, res, next) {
// logic
});
Responses from within a middleware function can be in any format, such as an HTML error page, a simple message, or a JSON string.
For organizational (and higher-level framework) purposes, you can define several error-handling middleware functions, much as you would with regular middleware functions. For example, to define an error-handler for requests made by using XHR
and those without:
var bodyParser = require("middleware").bodyParser;
app.use(bodyParser.urlencoded());
app.use(bodyParser.json());
app.use(logErrors);
app.use(clientErrorHandler);
app.use(errorHandler);
In this example, the generic logErrors
might write request and error information to stderr
, for example:
function logErrors(err, req, res, next) {
console.error(err.stack);
next(err);
}
Also in this example, clientErrorHandler
is defined as follows; in this case, the error is explicitly passed along to the next one.
Notice that when not calling “next” in an error-handling function, you are responsible for writing (and ending) the response.
function clientErrorHandler(err, req, res, next) {
if (req.xhr) {
res.status(500).send({ error: "Something failed!" });
} else {
next(err);
}
}
Implement the “catch-all” errorHandler
function as follows (for example):
function errorHandler(err, req, res, next) {
res.status(500);
res.render("error", { error: err });
}
Async Handle
WebApp
and WebApp.Router
support Async Handle
.
If your handle
function is an async
function, or returns a promise
object:
- If
promise
isreject
as anerror
object,WebApp
will callnext(error)
to handle it. - If
promise
isresolve
as a normal value,WebApp
will callres.send(value)
to send this value. - If
promise
isresolve
asundefined
,WebApp
will not do any processing.
In this way, we can support callback function style and async/await
at the same time with minimal cost. Although it is very free to do so, we strongly recommend using only one of them, because the application's error handling method should be consistent.
Example
- Use
async
handle andres.send
method:
function handle() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Hello world.");
}, 1000);
});
}
app.get("/", async function(req, res) {
var ret = await handle();
res.send(ret);
});
- Use
async
handle and return value:
function handle() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Hello world.");
}, 1000);
});
}
app.get("/", async function(req, res) {
var ret = await handle();
return ret;
});
- Use
async
handle andnext()
mehtod:
function handle() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Hello world.");
}, 1000);
});
}
app.use("/", async function(req, res, next) {
var ret = await handle();
console.log(ret);
next();
});
Stream Mode
The http protocol supports block transfer. The http header does not set Content-Length
, and Transfer-Encoding', 'chunked'
is set, and the data can be sent to the client in an http response.
With this feature, the server can work in stream mode. An http request does not have to be returned immediately, and the server pushes it to the client when the data is ready. Stream mode need to do the following:
res.write()
is used repeatedly in the http request reply, and finally ends withres.end()
.
Example
var socket = require("socket");
var WebApp = require("webapp");
var iosched = require("iosched");
var mw = require("middleware");
// Create app.
var saddr = socket.sockaddr("192.168.7.32", 8000);
var app = WebApp.create("app", 0, saddr);
app.route("/stream").get(function(req, res) {
res.type("html");
res.write("<html><body>");
var count = 0;
var timer = setInterval(() => {
res.write(`<h3>count: ${count++}</h3>`);
if (count === 20) {
res.end("</html></body>");
clearInterval(timer);
timer = null;
}
}, 1000);
req.on("close", () => {
if (timer) {
clearInterval(timer);
timer = null;
}
});
res.on("end", () => {
if (timer) {
clearInterval(timer);
timer = null;
}
});
});
// Catch 404 and forward to error handler.
app.use(function error(req, res, next) {
res.status(404);
next(new Error("Not Found"));
});
// Error handler.
app.use(function(err, req, res, next) {
if (res.headersSent) {
return next(err);
}
var status = err.status ? err.status : res.status();
status = status < 400 ? 500 : status;
res.json({ status: status, msg: err.message });
});
// Start app.
app.start();
// Event loop.
while (true) {
iosched.poll();
}
Example
A base app example
var socket = require("socket");
var WebApp = require("webapp");
var iosched = require("iosched");
// Create app.
var app = WebApp.create("app", 0, socket.sockaddr(socket.INADDR_ANY, 8000));
// Route and handle.
app.get("/", function index(req, res) {
res.send("Hello world!");
});
// Catch 404 and forward to error handler.
app.use(function(req, res, next) {
res.status(404);
next(new Error("Not Found"));
});
// Error handler.
app.use(function(err, req, res, next) {
if (res.headersSent) {
return next(err);
}
var status = err.status ? err.status : res.status();
status = status < 400 ? 500 : status;
res.json({ status: status, msg: err.message });
});
// Start app.
app.start();
// Event loop.
while (true) {
iosched.poll();
}
A comprehensiveapp app example
var socket = require("socket");
var WebApp = require("webapp");
var iosched = require("iosched");
var bodyParser = require("middleware").bodyParser;
// Create app.
var app = WebApp.create("app", 0, socket.sockaddr(socket.INADDR_ANY, 8000));
// Index page.
app.get("/", function index(req, res) {
// Handle request. If you encounter an error, you could return a Error.
// return new Error('error');
// Response as follow methods:
// res.render('index');
// res.send(text);
// res.json(object);
// res.sendStatus(statusCode);
var html = `
<html><body>
<H1>Hello world!</H1>
</body></html>`;
res.send(html);
});
app
.route("/use")
.use(function(req, res, next) {
// Verify the user.
next();
})
.get("/show", function(req, res) {
var id = req.params.id;
// Get user info by user id...
res.json({ id: id, name: "lisa", addr: "Beijing" });
})
.post("/add", bodyParser.urlencoded(), function(req, res) {
var post = body;
// Access and process data. post em. post.name, post.addr...
res.json({ result: "ok" });
});
// Catch 404 and forward to error handler.
app.use(function(req, res, next) {
res.status(404);
next(new Error("Not Found"));
});
// Error handler.
app.use(function(err, req, res, next) {
if (res.headersSent) {
return next(err);
}
var status = err.status ? err.status : res.status();
status = status < 400 ? 500 : status;
res.json({ status: status, msg: err.message });
});
// Start app.
app.start();
// Event loop.
while (true) {
iosched.poll();
}
A app porject example
The project organize as follow:
[/root/app1]
|-[public]..............static file.
| |-[css]
| |-[image]
| |-[html]
| |-[js]
|-[routers].............modules routers.
| |-index.js
| |-user.js
|-[views]...............render views.
| |-index.ejs
| |-error.ejs
|-[js]..................user modules.
|-app.js................app start file.
|-config.json...........config file.
- app.js:
var socket = require("socket");
var WebApp = require("webapp");
var iosched = require("iosched");
var mw = require("middleware");
var index = require("./routers");
var user = require("./routers/user");
// Create app.
var app = WebApp.create("app1", 0, socket.sockaddr(socket.INADDR_ANY, 8000));
// Static file handler, use internal middleware.
app.use("/public", mw.serveStatic("/root/app1/public"));
// Index.
app.use("/", index);
// User module router.
app.use("/user", user);
// Catch 404 and forward to error handler.
app.use(function(req, res, next) {
res.status(404);
next(new Error("Not Found"));
});
// Error handler.
app.use(function(err, req, res, next) {
if (res.headersSent) {
return next(err);
}
var status = err.status ? err.status : res.status();
status = status < 400 ? 500 : status;
res.json({ status: status, msg: err.message });
});
// Start app.
app.start();
// Event loop.
while (true) {
iosched.poll();
}
- routers/index.js:
var Router = require("webapp").Router;
var router = Router.create();
router.get("/", function(req, res) {
res.render("index", { title: "JSRE" });
});
module.exports = router;
- routers/user.js:
var Router = require("webapp").Router;
var bodyParser = require("middleware").bodyParser;
var router = Router.create();
router
.use(function(req, res) {
// Verify the user.
})
.get("/show", function(req, res) {
var id = req.params.id;
// Get user info by user id...
res.json({ id: id, name: "lisa", addr: "Beijing" });
})
.post("/add", bodyParser.json(), function(req, res) {
var post = req.body;
// Access and process data. post em. post.name, post.addr...
res.json({ result: "ok" });
});
module.exports = router;
- views/index.ejs:
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
</head>
<body>
<h1><%= title %></h1>
<p>Welcome to <%= title %></p>
</body>
</html>
- views/error.ejs:
<!DOCTYPE html>
<html>
<body>
<h1>Status: <%= status %></h1>
<p>Error info: <%= msg %></p>
</body>
</html>