flatiron.js / union - where to put app.use() configuration? - javascript

Taking the simple example from Union, I am wondering where I can put configuration code that usually goes in app.configure, like passport.js:
app.configure(function() {
// Initialize Passport! Also use passport.session() middleware, to support
// persistent login sessions (recommended).
app.use(passport.initialize());
app.use(passport.session());
});
Any ideas? server and router don't accept use().

Union appears to use the before collection for this:
var server = union.createServer({
before: [
connect.session({ secret: 'keyboard cat' }), // for `passport.session()`
passport.initialize(),
passport.session(),
// etc.
]
});
From the "API" documentation:
#option before {Array}
The `before` value is an array of middlewares, which are used to route and serve incoming
requests. For instance, in the example, `favicon` is a middleware which handles requests
for `/favicon.ico`.

Union supports connect middlewares via the before property, as previously mentioned by others. However, union does not handle application configuration; flatiron does. The api, however, is significantly different from express.
For example, configuring an application may look something like this:
var path = require('path'),
flatiron = require('flatiron'),
app = flatiron.app,
plugins = flatiron.plugins,
connect = require('connect'), // most connect middlewares work with flatiron ootb
passport = require('passport');
// Use flatiron's http plugin (not the same as a middleware!)
app.use(plugins.http);
// configuration consists of key/value pairs, not of function blocks associated with
// certain "environments".
// Here's *a* way you can handle environment-based configs; there are others!
app.config.file(path.resolve(
__dirname,
'config',
(process.env.NODE_ENV || 'config') + '.json'
));
// Use our config to set the secret
app.http.before.push(connect.session({
secret: app.config.get('secret') || 'keyboard cat' //default
}))
app.http.before.push(passport.initialize());
app.http.before.push(passport.session());
I haven't tried running this example (I'm sure there are more details here) but hopefully this gives you an idea.

I just built a wrapper to integrate Passport.js with Flatiron.js.
https://npmjs.org/package/flatiron-passport
https://github.com/travist/flatiron-passport
Please read the README.md on how to use it and apply it to your application.
I have tested it on LocalStrategy, but it should work for other strategies.
Please let me know otherwise.

Related

Call a router WITHIN Nodejs after a route has been called

I am using Expressjs and the Auth0 API for authentication and ReactJs for client side.
Because of the limitations of the Auth0 API (spoke with their team) I am sending updated user details to my backend and then using app.set() to be able to use the req.body in another route.
I need to call the app.patch() route automatically after the app.post() route has been hit.
The end goal is that the users data will be updated and shown client side.
const express = require('express');
const cors = require('cors');
const path = require('path');
const app = express();
require('dotenv').config()
const { auth } = require("express-openid-connect");
app.use(express.json());
app.use(cors());
app.use(express.static(path.join(__dirname, 'build')));
app.use(
auth({
issuerBaseURL: process.env.AUTH0_ISSUER_BASE_URL,
baseURL: process.env.BASE_URL,
clientID: process.env.AUTH0_CLIENT_ID,
secret: process.env.SESSION_SECRET,
authRequired: false,
auth0Logout: true,
})
);
app.get('/', async (req, res) => {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
app.get('/api', async (req, res) => {
const stripe = require('stripe')(`${process.env.REACT_APP_Stripe_Live}`);
const invoice = await stripe.invoices.list({
limit: 3,
});
res.json(invoice);
});
app.post('/updateuser', (req, ) => {
app.set('data', req.body);
})
app.patch(`https://${process.env.AUTH0_ISSUER_BASE_URL}/api/v2/users/:id`,(req,res) => {
let val = app.get('data');
req.params = {id: val.id};
console.log(req.params);
})
app.listen(process.env.PORT || 8080, () => {
console.log(`Server listening on 8080`);
});
I'd suggest you just take the code from inside of app.patch() and make it into a reusable function. Then it can be called from either the app.patch() route directly or from your other route that wants to do the same funtionality. Just decide what interface for that function will work for both, make it a separate function and then you can call it from both places.
For some reason (which I don't really understand, but seems to happen to lots of people), people forget that the code inside of routes can also be put into functions and shared just like any other Javascript code. I guess people seems to think of a route as a fixed unit by itself and forget that it can still be broken down into components and those components shared with other code.
Warning. On another point. This comment of yours sounds very wrong:
and then using app.set() to be able to use the req.body in another route
req.body belongs to one particular user. app.set() is global to your server (all user's requests access it). So, you're trying to store temporary state for one single user in essentially a global. That means that multiple user's request that happen to be in the process of doing something similar will trounce/overwrite each other's data. Or worse, one user's data will accidentally become some other user's data. You cannot program a multi-user server this way at all.
The usual way around this is to either 1) redesign the process so you don't have to save state on the server (stateless operations are generally better, if possible) or 2) Use a user-specific session (like with express-session) and save the temporary state in the user's session. Then, it is saved separately for each user and one user's state won't overwrite anothers.
If this usage of app.set() was to solve the original problem of executing a .patch() route, then the problem is solved by just calling a shared function and passing the req.body data directly to that shared function. Then, you don't have to stuff it away somewhere so a later route can use it. You just execute the functionality you want and pass it the desired data.

Fastify middleware - access to query and params?

trying to get middleware working in Fastify - I don't seem to have access to the query or params. The docs say:
Fastify supports out of the box Express/Restify/Connect middlewares, this means that you can just drop-in your old code and it will work! (faster, by the way)
But with a simple example:
fastify.use(function(req, res, next) {
console.log('req.query', req.query); // undefined
console.log('req.params', req.params); // undefined
next();
});
Same if I add/restrict the url:
fastify.use('/foo', function(req, res, next) {
I'm sure I am missing something, but the docs do claim it 'just works' - which I can't see how if you don't get access to the qs?
[I think I can re-write to use hooks, but I'm really interested in how I am meant to be doing this with middleware]
Thanks
This was answered when Fastify 2 was the main version. This answer may not be correct for Fastify 3
While Fastify is compatible with Express/Restify method signature, it isn't exactly the same values being passed in. The method signature is:
/**
* Generic middleware method
* #param {http.IncomingMessage} req
* #param {http.ServerResponse} res
*/
const middleware = (req, res) => {
}
fastify.use(middleware)
When using .use, Fastify only deals with the Node.js HTTP classes
which do not provide the .params or .query fields.
Express adds these fields as a nicety to developers. If the middleware you use
relies on those features, unfortunately, it will not be a direct drop in.
All is not lost
If you choose to migrate your middleware to Fastify, the .params and .query
fields are available on the Request
object.
Using the middleware in your question, this is what the Fastify version would
look like.
fastify.addHook('onRequest', function(request, reply, done) {
console.log('query', request.query);
console.log('params', request.params);
done();
})
Fastify is asking developers to think more in terms of Hooks and less in terms of Middleware. This provides more flexibility and greater speed but can be a little more complicated to write at times.
Additional reading
The Lifecycle and
Hooks documentation on the Fastify
site give more detail on how these pieces work together.
The Middleware documentation
provides more detail on what features are supported.
Somewhat related, using Plugins
you are able to scope to a particular path.
References
Express middleware support
From the Middleware documentation:
Furthermore, methods added by Express and Restify to the enhanced versions of
req and res are not supported in Fastify middlewares.
and
Express modifies the prototype of the node core Request and Response objects
heavily so Fastify cannot guarantee full middleware compatibility.
Express adding .params and .query
Express adding .query to request
and where Express runs the query middleware
Express adding parameters to route.
The .use() function is only a utility to help users to migrate from Express to Fastify.
The input function interface is (req, res, next) but the req and res object are
the standard Node.js objects http.ClientRequest
and http.ServerResponse (that is the same
interface of Express middleware).
So the assumption is that the users have implemented middleware for Express using the standard Node.js's objects.
To archive your needs you should parse the req.url as described here.
The .use API will be deprecated in Fastify v3.
Instead, if you want to start developing with Fastify you should migrate to .register.
The register is the great feature of Fastify that offer encapsulation
I Fastify use method is used for registering middlewares. The middleware is a function with the following signature middleware(err, req, res, next)
Try:
fastify.use(function(err, req, res, next) {
console.log('req.query', req.query); // undefined
console.log('req.params', req.params);
next();
});
You can use fastify without .use method , just use fastify.route.
fastify.route({
method: 'GET',
url: '/',
schema: {
// request needs to have a querystring with a `name` parameter
querystring: {
name: { type: 'string' }
}
},
handler: async (request, reply) => {
// here you will get request.query if your schema validate
}
})

How to fix timeout on express http-proxy-middleware

I am setting up an express server with http-proxy-middleware. When requesting from the proxy, the request goes on until it finally times out.
The URL I try to proxy is https://www.pegelonline.wsv.de/, especially a WFS it provides. I've read the docs, and the TL;DR seems to apply for my case since I don't aim to do anything special that's listed. I've also tried the shorthand.
https://github.com/chimurai/http-proxy-middleware#tldr
Minimal example:
https://github.com/isthisstackoverflow/repro-waterlevel
const proxy = require('http-proxy-middleware')
const express = require('express')
const app = express()
const port = 9004
app.use(
'/',
proxy({
target: 'https://www.pegelonline.wsv.de/',
changeOrigin: true
})
)
app.listen(port)
https://pegelonline.wsv.de/webservices/gis/aktuell/wfs?service=wfs&version=1.1.0&request=GetFeature&typeName=gk:waterlevels&outputFormat=json&Filter=%3CFilter%3E%3COr%3E%3CPropertyIsEqualTo%3E%3CPropertyName%3Ewater%3C/PropertyName%3E%3CLiteral%3EESTE%3C/Literal%3E%3C/PropertyIsEqualTo%3E%3C/Or%3E%3C/Filter%3E
^ Result is as expected.
http://localhost:9004/webservices/gis/aktuell/wfs?service=wfs&version=1.1.0&request=GetFeature&typeName=gk:waterlevels&outputFormat=json&Filter=%3CFilter%3E%3COr%3E%3CPropertyIsEqualTo%3E%3CPropertyName%3Ewater%3C/PropertyName%3E%3CLiteral%3EESTE%3C/Literal%3E%3C/PropertyIsEqualTo%3E%3C/Or%3E%3C/Filter%3E
^ Timeout eventually.
Update
I figure the problem is me trying to proxy https to http. I don't know what exactly the problem was and no longer need to do this, though.

Best way to store DB config in Node.Js / Express app

What would be the best way to store DB config (username, password) in an open source app that runs on node.js / Express? Two specific questions:
Shall I put it into a separate config.js file in /lib folder, for example, and never include it into the master repository that is publicly available on GitHub?
To inlcude the config, is it as simple as require('./config.js') from the file that needs it or is there a better way of doing it?
PS sorry if the questions seem a bit simple or not so well formulated, but I'm just starting :)
Here's how I do it:
Create a config.js which contains objects representing your configs:
var config = {
development: {
//url to be used in link generation
url: 'http://my.site.com',
//mongodb connection settings
database: {
host: '127.0.0.1',
port: '27017',
db: 'site_dev'
},
//server details
server: {
host: '127.0.0.1',
port: '3422'
}
},
production: {
//url to be used in link generation
url: 'http://my.site.com',
//mongodb connection settings
database: {
host: '127.0.0.1',
port: '27017',
db: 'site'
},
//server details
server: {
host: '127.0.0.1',
port: '3421'
}
}
};
module.exports = config;
Then in my index.js (or wherever really),
var env = process.env.NODE_ENV || 'development';
var config = require('./config')[env];
Then process with that object, e.g.
var server = express();
server.listen(config.server.port);
...
For running toy apps where I need to hide db credentials, I use the dotenv module.
Place your sensitive info in a .env file (which is .gitignored), place require('dotenv').config(); in your app; dotenv creates entries in process.env that you can refer to.
.env file:
DATABASE_PASSWORD=mypw
DATABASE_NAME=some_db
To refer to the values:
process.env.DATABASE_PASSWORD
Not sure whether this is the best practice, but personally I have a config.json file where I store my db connection information. Then I do the following:
// options.js
var fs = require('fs'),
configPath = './config.json';
var parsed = JSON.parse(fs.readFileSync(configPath, 'UTF-8'));
exports.storageConfig= parsed;
Then from a different file I do the following:
var options = require('./options');
var loginData = {
host: options.storageConfig.HOST,
user: options.storageConfig.user,
password: options.storageConfig.password
};
I do put in args. just like the port of so many node.js example.
you most likely forever, pm2, nodemon to run your app. so this variable is not check in as part of your source code. and they are globally available too.
process.env.PORT
process.env.DATABASE_USER
process.env.DATABASE_PASSWORD
PORT=3000 DATABASE_HOST=localhost DATABASE_USER=admin DATABASE_PASSWORD=mypassword node app.js
export PORT=3000
export DATABASE_HOST=localhost
export DATABASE_PORT=27017
export DATABASE_USER=admin
export DATABASE_PASSWORD=mypassword
node app.js
var server = app.listen(process.env.PORT, function() {
});
var mongoClient = new MongoClient(new Server(process.env.DATABASE_HOST, process.env.DATABASE_PORT));
To inlcude the config, is it as simple as require('./config.js') from the file that needs it or is there a better way of doing it?
This is the right way to store config files.
The best approach would be to write your entire application like an ordinary node.js module, and write a small start-up file that calls it. This idea also allow you to use different database drivers using dependency injection.
Good, but not perfect solution is the environment. It is shared among all application, so if you have certain data you want to be available to all of them, this is the best bet. But if you have a config for one particular app, not much so.
PS: And please, don't use JSON for this. It's the worst idea possible. :)
I found this a nice way to handle my config, considering different environments:
config.coffee
exports.setEnvironment = (env) ->
switch env
when "development"
exports.DEBUG_LOG = true
exports.DB_PORT = '27017'
# ...
when "testing"
exports.DEBUG_ERROR = true
exports.DEBUG_CLIENT = true
# ...
when "production"
exports.DEBUG_LOG = false
# ...
else console.log "environment #{env} not found"
server.coffee:
config = require('./config')
config.setEnvironment env
Using environment variables
You can use export to set environment variables in OSX and Linux. The following is an example of setting a value in the SESSION_SECRET key.
export SESSION_SECRET="keyboard cat"
In Windows, you can use set.
set SESSION_SECRET="keyboard cat"
You can also set environment variables each time you run them.
SESSION_SECRET="keyboard cat" node secret-env.js
Use process.env of node.js to access environmental variables within code.
var express = require('express')
var session = require('express-session')
var app = express()
app.use(session({secret: process.env.SESSION_SECRET}))
Request a argument from the command-line
The best way to protect confidential information is not to store it in a setup file.
If the command-line requests configuration information as an argument using the noopt package, the secret information does not need to exist as a file.
The following is an example of requesting a session key as an argument using the noopt package.
var nopt = require("nopt")
var longOpts = {
"sessionSecret": String,
}
var shortOpts = {
"s": ["--sessionSecret"],
}
var parsed = nopt(longOpts, shortOpts, process.argv, 2)
console.log("session secret is:", parsed.sessionSecret)
node secret-arg.js --sessionSecret "keyboard cat"
node secret-arg.js -s "keyboard cat"
Advantages : It is safer to expose confidential information than to hardcoding or having it as a configuration file.
Disadvantages : There is a hassle of increasing the amount of information to be entered each time the app is launched.
If you try to create and solve a script, the problem that the password still exists in the script remains.

How to store session values with Node.js and mongodb?

How do I get sessions working with Node.js, express#2.0.0 and mongodb? I'm now trying to use connect-mongo like this:
var config = require('../config'),
express = require('express'),
MongoStore = require('connect-mongo'),
server = express.createServer();
server.configure(function() {
server.use(express.logger());
server.use(express.methodOverride());
server.use(express.static(config.staticPath));
server.use(express.bodyParser());
server.use(express.cookieParser());
server.use(express.session({
store: new MongoStore({
db: config.db
}),
secret: config.salt
}));
});
server.configure('development', function() {
server.use(express.errorHandler({
dumpExceptions: true,
showStack: true
}));
});
server.configure('production', function() {
server.use(express.errorHandler());
});
server.set('views', __dirname + '/../views');
server.set('view engine', 'jade');
server.listen(config.port);
I'm then, in a server.get callback trying to use
req.session.test = 'hello';
to store that value in the session, but it's not stored between the requests.
It probobly takes something more that this to store session values, how? Is there a better documented module than connect-mongo?
Take a look at this series from DailyJS. It uses MongoDB and session management
http://dailyjs.com/tags.html#lmawa
I am not experienced with Node.js or Express, so I cannot immediately see what's wrong with your approach. However, I have made Express use MongoDB to store sessions for flash messages and other session stuff.
You can see my source code for a simple URL shortener here (that actually makes the URLs pretty long at the moment - it was just an exercise ;)). I use the session to store a list of URLs that the current user has shortened.
It is not pretty, but I know it works.

Categories

Resources