Express: passing options to an included server - node.js

I would like to develop an Express website that can run either stand-alone or as part of a larger server while allowing a degree of configuration.
For example, say I have a large main server in server.js and I write another server app.js that defines a route /* to provide a small service. I want to be able to either:
run app.js standalone, which will provide its routes through localhost:port/
define a route within server.js that maps to this server, for example so that /app/* will allow app.js to handle requests.
Reading through Smashing Node, I see that if I define an Express server and its routes in app.js, I can use: server.use('/app', require('app.js') to gain use of its routes. The problem with this approach is that I do not see how to pass any configuration options to app.js.

You could write your app.js module as a callable function:
var express = require("express");
var app; // <-- note the global
var initialize = function(conf) {
if (app) {
return app;
}
conf = conf || {};
app = express();
// here goes the configutation code, for example:
if (conf.static) {
app.use(express.static(conf.static));
}
return app;
};
if (require.main === module) {
// if standalone, fire it
initialize({ static: __dirname + "/public" });
}
// and export
module.exports = exports = initialize;
and then in other file:
var app = require("app.js")({ static: __dirname + "/public" });
Note that it is a singleton, so further calls to the module function will return the same server:
app == require("app.js")();
I'm sure you can tweak it to your needs.

Related

What is the convention of separating APIs as modules in NodeJS?

Here is how my app.js looks like...
I want to know how do I separate this single file into multiple files for better code quality. How do we do that?
My idea is to have the below files...
server.js -> for server related properties
serve.js -> this becomes the main file in the package.json
apis -> this shall be the file with apis, I shd be able to separate apis depending upon the modules too...
What is the preferred convention in NodeJS? I am sure that we do not want to write all apis in one single file.
const express = require('express') // import express module
const app = express() // initiate express app
app.use(express.json()) // not sure what this is but without it POST cant read the JSON parameters from the body
const host = 'localhost' // host
const port = process.env.PORT || 1338 // pick port
const routePrefix = '/' + 'api' + '/' // this is the route prefix used from where the APIs will be accesssed
const routes = { // define routes
root: routePrefix + 'root',
test: routePrefix + 'test',
items: routePrefix + 'items',
item: routePrefix + 'items/:id'
}
// print details
function printDetails(currentRoute, requestMethod, requestParams,
requestQuetyString) {
console.log(currentRoute, requestMethod, requestParams, requestQuetyString);
}
// get root
app.get(routes.root, (req, res) => {
printDetails(routes.root, req.method, req.params, req.query)
res.send(routes.root)
})
// get test route
app.get(routes.test, (req, res) => {
printDetails(routes.test, req.method, req.params, req.query)
res.send(routes.test)
})
// for the web server
app.use(express.static('../public')) // this is where static files reside and need to be served to for the clientside app
// start the API server and Web server
app.listen(port, () => {
console.log(`
\nExpress Server started on port ${port}..
APIs can be accessed at http://${host}:${port}${routePrefix}
Web Server started on port http://${host}:${port}
`)
})
I have tried it on my own and the respective files look like this. However, I am unable to run this.
server.js
const express = require('express') // import express module
const app = express() // initiate express app
app.use(express.json()) // not sure what this is but without it POST cant read the JSON parameters from the body
//const api = require('./apis')
//const app = api.app
const host = 'localhost' // host
const port = process.env.PORT || 1338 // pick port
const routePrefix = '/' + 'api' + '/' // this is the route prefix used from where the APIs will be accesssed
const routes = { // define routes
root: routePrefix + 'root',
test: routePrefix + 'test',
items: routePrefix + 'items',
item: routePrefix + 'items/:id'
}
// for the web server
app.use(express.static('../public')) // this is where static files reside and need to be served to for the clientside app
module.exports = {
app: app,
host: host,
port: port,
routePrefix: routePrefix,
routes: routes
}
serve.js
const server = require('./server') // import server module
//const app = server.app
// start the API server and Web server
server.app.listen(server.port, () => {
console.log(`
\nExpress Server started on port ${server.port}..
APIs can be accessed at http://${server.host}:${server.port}${server.routePrefix}
Web Server started on port http://${server.host}:${server.port}
`)
})
api.js
'use strict'
const server = require('./server') // import sever module
const app = server.app
// get test route
app.get(server.routes.test, (req, res) => {
printDetails(server.routes.test, req.method, req.params, req.query)
res.send(server.routes.test)
})
module.exports = {
}
The problem I am facing is how do I use module.exports and what do I need to export from what module. My requirement is when I run "node serve.js", I should be able to run the APIs and they should be available for the client. How do I achieve this?
I think that the following structure is much more maintainable and easier to understand (also this is the more commonly used structure in new web apps in node):
├───client <-- Your web client application directory
│ └───assets
├───common <-- Common (shared) files between client and server
└───server <-- Your SugoiJS server directory
├───config <-- Build config (environment, webpack)
│ └───webpack
└───src <-- Your server app source code
├───app <-- Bootstrap module, Server initialize and listener files, 'authorization' class(optional)
│ └───classes
├───config <-- Server configuration (services, paths, etc.)
└───modules <-- All of you application modules
└───index <-- Single module
├───controllers <-- Modules' controllers
├───models <-- Modules' models(optional)
└───services <-- Modules' services
This is taken from SugoiJS framework.
https://wiki.sugoijs.com/get-started
Then basically all the routes you are writing will be controllers :)
There are many ways to split up JS code into files, the simplest way (that is still quite efficient) is to require modules. Here's a full guide, and here's a minimal demo:
// lib.js
module.exports = {
x: 10,
y: () => 20
}
// index.js
const lib = require('./lib');
console.log(lib.x); // 10
console.log(lib.y()); // 20
To keep the code clear, simple and efficient, requiring a module should not have any side effects (ie deleting a file, or making requests): for example, define a Class inside a module, and export it.
There are other ways to split up code between files, such as import/export.

Is it possible to have different route files in Express (NodeJS) app?

I'm a NodeJS beginner and I'm using express. My directory is like this :
__app
|_assets
|_controllers
|_somemodel.controller.js
|_models
|_somemodel.model.js
|_user.model.js
|_routes
|_route.js
|_passport.routes.js
|_somemodel.routes.js
|_views
|_note
|_index.ejs
|_passport
|_index.ejs
|_login.ejs
|_profile.ejs
...
__config
|_database.config.js
|_passport.config.js
__node_modules
package.json
server.js
the thing I wanna know is that is it possible to have a general routes file and then include or require other route files in that ? Like my route.js ?
And is this directory correct while using Express and Passport as authentication?
yes, you can require other route files into a common file like bellow.
somemodel.contoller.js
module.exports.someMethod = (req, res) => {
// do something
}
somemodel.routes.js
const controller = require("path-to-somemodel-controller")
module.exports = (app) {
app.route("/somepath")
.get(controller.someMethod)
// other methods
}
route.js
// you need to parse the app into route module
module.exports = (app) => {
require('somemodel.routes')(app);
// others goes here
}
server.js
const app = express();
require('path-to-route.js')(app
)

Express: how can I get the app from the router?

I know I can get the Express app from inside an individual route with:
req.app
However I need to start a single instance of a module inside routes/index.js, i.e.:
var myModule = require('my-module')(propertyOfApp)
How can I get the express app from the router?
It really depends on your own implementation, but what I suggested in the comments should be working:
// index.js
module.exports = function(app) {
// can use app here
// somehow create your router and do the magic, configure it as you wish
router.get('/path', function (req, res, next) {});
return router;
}
// app.js
// actually call the function that is returned by require,
// and when executed, the function will return your configured router
app.use(require('./index')(app));
p.s.
Of course this is just a sample - you can configure your router with path, and all kind of properties you wish. Cheers! :)

Call twice the app variable in an express application

I have a file where I call all the require modules called 'app.js'
var express = require('express');
...
var app = express();
...
var routes = require('ruotes/index.js)
use('/', routes);
module.exports = app;
I call the index.js where I have all the routes
routes/index.js
var express = require('express');
var app = express();
/* import controllers */
var indexController = require('../controllers/index');
app.route('/')
.get(indexController.index);
module.exports = app;
The problem is I have two variables called app and I call twice express(). Does it exist a more elegant way to handle this situation? Maybe I could call the variable in router file in another way?
You are currently using a technique that is known as submounting.
If you want to avoid creating different instances of Express, you will have to pass your unique instance of Express as a parameter to your router, meaning that your index.js needs to export a function that accepts your app as a parameter.
Something like :
//=== routes/index.js
/* import controllers */
var indexController = require('../controllers/index');
module.exports = function(app){
app.route('/').get(indexController.index);
};
Doing so will allow you to keep the same instance of Express in your entire Web App.
Since you exported a function in index.js, you need to call it in app.js.
var express = require('express');
...
var app = express();
...
var routes = require('routes/index.js)(app)
module.exports = app;
You can use the same technique for routes, modules, models etc...
This technique will allow you to avoid re-requiring modules, and instantiating them, but you will need to write extra-bits to make sure your variables are passed from one side of your app to the other. Because of this, some prefer using the submounting technique, and requiring modules only where they are needed.

Express: accessing app.set() settings in routes

In Express, I'm led to believe that global app settings can be created by doing something similar to the following in my main app.js file:
var express = require('express'),
...
login = require('./routes/login');
var app = express();
app.configure(function(){
...
app.set('ssoHostname', 'login.hostname.com');
...
});
...
app.get('/login', login.login);
...
now in ./routes/login.js, I'd like to access app.settings.ssoHostname, but if I attempt to run anything similar to (as per: How to access variables set using app.set() in express js):
...
exports.login = function(req, res) {
var currentURL = 'http://' + req.header('host') + req.url;
if (!req.cookies.authCookie || !User.isValidKey(req.cookies.authCookie)) {
res.redirect(app.settings.ssoHostname + '/Login?returnURL=' + encodeURIComponent(currentURL));
}
};
...
it does not recognize app:
ReferenceError: app is not defined
My questions are:
Is the approach I took of using app.set() for global settings that will be re-used often the "proper" way to do it and if so...
How do I access these settings in routes?
If not using app.set() for global settings to be used often, how would I set and get custom settings in routes?
Use req.app.get('ssoHostname')
At the end of your app.js file:
module.exports = app;
And then in routes/login.js:
var app = require('../app');
Now you have access to the actual app object and won't get a ReferenceError.

Resources