let api = connect()
.use(users.users)
.use(pets.pets)
.use(errorHandler.errorHandler);
let app = connect()
.use(hello.hello)
.use('/api', api)
.use(errorPage.errorPage)
.listen(3000);
source code in Nodejs in action..
it doesn't work. => 'api' is never called. it's nothing happen when URL is /api.
how can i fix it?
pets.js
module.exports.pets = function pets(req, res, next) {
if (req.url.match(/^\/pet\/(.+)/)) {
foo();
}
else{
next();
}
}
users.js
let db = {
users: [
{name: 'tobi'},
{name: 'loki'},
{name: 'jane'}
]
};
module.exports.users = function users(req, res, next) {
let match = req.url.match(/^\/user\/(.+)/);
if(match) {
let user;
db.users.map(function(value){
if(value.name == match[1])
user = match[1];
});
if(user) {
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify(user));
}
else {
let err = new Error('User not found');
err.notFound = true;
next(err);
}
}
else {
next();
}
};
and connect version is
"connect": "^3.6.6"
is it possible 'connect(app)'?
You shouldn't instantiate two connect servers. What you want to do is chain those middlewares as
.use('/api', users.users);
.use('/api', pets.pets);
The first middleware will pass the request onto pets.pets via next().
You can read more at this link. Sadly connect doesn't support this type of chaining:
.use('/api', [users.users,pets.pets]);
Which would be a cute solution to your problem, but express supports it.
So if you're looking into NodeJS, you should definitely get familiar with Express, Connect is a good starting tool but it's as simple as it gets without any decent functionality without some 'hacking' on your side.
Related
I have NODE.js code which works perfectly locally (127.0.0.1:CUSTOM_PORT). But now I would like to set it up to run it on Google Cloud Function.
This is the code which I'm using to run code locally:
function connect_to_server() {
const PORT = process.env.PORT || 8080;
app.listen(PORT,'127.0.0.1',function () {
console.log('---> SERVER IS RUNNNG <---')
})
}
Does someone know the way to set a running server with Google Cloud Functions?
What port should I use and URL INSIDE THE NODE.JS ?? Or I do not need to use it at all as GCF already initially set up a server for me?
GCF Provide trigger URL which can be hit, but it still does not work.
Full function with out app.listen()
// CONFIGURATION
const express = require('express')
const app = express()
const config = require('./config')
const bodyParser = require('body-parser')
const moment = require('moment')
const sql = require("mssql")
const jwt = require('jwt-simple')
const compression = require('compression')
function token(token) {
var secret = Buffer.from('xxx', 'hex')
return jwt.decode(token, secret)
}
function sql_puller(res, req) {
sql.connect(config, function (err) {
if (err) {
console.log(err)
res.send(err.code)
}
const request = new sql.PreparedStatement()
const {
x
} = req.body
let newProps = {}
x.forEach(filters => {
newProps[filters.x] = filters.x
})
const isValidInput = validateInput(x, x, x, res)
if (!isValidInput) {
return
}
request.input('1', sql.VarChar(1))
request.input('2', sql.VarChar(1))
request.input('3', sql.VarChar(1))
sqlQuery = `XXXXXX`
request.prepare(sqlQuery, err => {
if (err) {
console.log(err)
res.send(err.code)
return
}
request.execute({
iso: x,
start: x,
end: x
}, (err, recordset) => {
request.unprepare(err => {
if (err) {
console.log(err)
res.send(err.code)
return
}
})
if (err) {
console.log(err)
res.send(err.code)
return
}
res.json(recordset)
sql.close()
})
})
})
sql.on('close', function (err) {
console.log('SQL Connection Closed.', err)
})
sql.on('error', function (err) {
sql.close()
console.log('SQL error occurred.', err)
})
}
exports.main = function main() {
app.use(compression())
app.use(bodyParser.json())
app.post('/', function (req, res) {
try {
res.setHeader('Cache-Control', 'public, max-age=3600')
var decodedToken = token(req.body['Token'])
console.log(req.body)
console.log('Successefully connected - token accepted')
// connect to your databas
if (decodedToken == "XXXXXX") {
sql_puller(res, req)
} else {
console.log('Incorrect Token')
}
} catch (err) {
if (err) {
console.log(err)
res.send('Invalid Token')
return
}
}
})
}
You cannot the way you have designed it. Google Cloud Functions has a maximum runtime and then the function is terminated. As of today this limit is 540 seconds. Cloud Functions are invoked by an outside process, Cloud Functions do not wait for someone to connect to them (e.g. they don't listen, they are not asleep). The exception is HTTP Trigger, but this is not usable to present a website, but can be usable for actions.
There are companies that run their entire website using Cloud Functions, Cloud Datastore and Cloud Storage. The magic is using an API gateway product. An API gateway provides the URL, www.example.com, that customers go to. The API gateway then invokes Cloud Functions to handle the request. You create similar mappings for each page on your serverless website to Cloud Functions.
Many developers use Google App Engine to accomplish what you are trying to do. Very low cost and very easy to develop for. Another excellent Google product for you to consider is Google Firebase. Google has many other products that are not serverless such as Containers on Compute Engine and Kubernetes.
I want to use gridfs-stream in a nodejs application.
A simple example is given in the documentation:
var mongoose = require('mongoose');
var Grid = require('gridfs-stream');
Grid.mongo = mongoose.mongo;
mongoose.connect('mongodb://localhost:27017/test');
// make sure the db instance is open before passing into `Grid`
mongoose.connection.once('open', function () {
var gfs = Grid(mongoose.connection);
// all set!
})
My problem is described by the comment:
make sure the db instance is open before passing into Grid
I try to use gfs in a post request. Now when the code gets initialized, the gfs variable is not defined yet.
api.post('/upload', function(req, res) {
req.pipe(gfs.createWriteStream({
filename: 'test'
}).on('close', function(savedFile){
console.log('file saved', savedFile);
return res.json({file: savedFile});
}));
})
Initializing my route from a callback seems kind of odd.
I read in this post (Asynchronous initialization of Node.js module) that require('') is performed synchronous, and since I rely on the connection being established, I'm kind of forced to wait
Basically I'm not sure if I should use a async pattern on startup now, or if I just miss a more elegant way to solve this.
I have a very similar problem with my server. In my case I am reading https certs asynchronously, the software version from git asynchronously and I want to make sure I have it all together by the time the user comes to log in so I can pass the software version back as a reply to login.
The solution is to use promises. Create the promises on user start up for each activity. Then in the code where you want to be sure its all ready, just call then on either the promise itself or Promise.all(array of promises).then()
Here is an example of what I am doing to read the ssl certs to start the server
class Web {
constructor(manager,logger) {
var self = this;
this.server = false;
this.logger = logger;
var key = new Promise((resolve,reject) => {
fs.readFile(path.resolve(__dirname, 'key.pem'),(err,data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
var cert = new Promise((resolve,reject) => {
fs.readFile(path.resolve(__dirname, 'certificate.pem'), (err,data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
Promise.all([key,cert]).then(values => {
var certs = {
key: values[0],
cert: values[1],
};
return certs;
}).then(certs => {
self.server = require('http2').createServer(certs,(req,res) => {
// NOW Started and can do the rest of the stuff
});
self.server.listen(...);
});
NEEDS SOME MORE CLOSING BRACKETS
and thanks to be there.
Issue :
I'm making a tiny mongoose "middleware" to handle a mongoose error :
// callback function called at each mongoDB response
var handleDbRes = function(callback) {
return function (err, entries) {
if (err) {
err.status = 500;
return next(err);
}
return callback(entries) // that line throw the exception
}
};
And so I'm using it into an api endpoint, e.g. :
someRouter.get('/', function(req, res) {
models.article.find(handleDbRes(res.json))
})
With that code, I encounter an error :
TypeError: Cannot call method 'get' of undefined
I followed the exception and looked at res.json() declaration, when debugging, I figured out :
var app = this.app;
var *** = app.get('***') // that line throw the exception
I guess that app is not defined cause app doesn't exists in "this".
Please can you help me to solve this problem ? I think that the reason is simple but I don't get it...
Thanks you for listening ;)
EDIT : I tried to res.json.bind(res) and it worked, as I thought, but that's really awful to bind this way for most api endpoint and I guess there is another way to do that kind of functionality without that.
EDIT : Thanks to Mscdex advices, I modified my code this way :
.get('/', function(req, res, next) {
models.article.find(handleDbRes(res.json.bind(res), next))
...
...
// callback function called at each mongoDB response
var handleDbRes = function(successCallback, errorCallback) {
return function (err, entries) {
if (err) {
err.status = 500;
return errorCallback(err);
}
return successCallback(entries)
}
};
When you pass res.json, the context for the json() function is lost (it no longer knows what this is because it is not bound). So here are a few possible solutions:
Use a bound version of the function so that this inside json() will always evaluate correctly:
someRouter.get('/', function(req, res) {
models.article.find(handleDbRes(res.json.bind(res)))
})
Or use a wrapper function instead:
someRouter.get('/', function(req, res) {
function respondJSON(val) {
res.json(val);
}
models.article.find(handleDbRes(respondJSON))
})
Or just pass in res and call res.json() inside handleDbRes():
someRouter.get('/', function(req, res) {
models.article.find(handleDbRes(res))
})
// callback function called at each mongoDB response
var handleDbRes = function(res) {
return function(err, entries) {
if (err) {
err.status = 500;
return next(err);
}
res.json(entries);
}
};
The other problem is that handleDbRes() doesn't have access to next, so you need to also pass that function in for when you run into an error.
Can you please help me make a connection persistent script. I used jsftp node module to connect to ftp server. What I need to do is to check if the user is already authenticated every time he send a request. Thanks in advance! here's my code:
var Ftp = require('jsftp');
var dumpLog = function (event){
console.log('Code: '+ event.code);
console.log('Message: '+ event.text);
}
var FtpController = {
index : function (req , res) {
res.view('ftp/login');
},
auth : function (req , res){
// Initialize some common variables
var user = req.param('user');
var pass = req.param('pass');
var ftp = new Ftp({
host: req.param('host'),
port: req.param('port') // Defaults to 21
});
ftp.auth( user, pass, function (err , auth_res){
if (err) throw err;
dumpLog(auth_res);
});
res.view('ftp/folder');
},
serve_folder : function(req,res){
res.view('ftp/folder');
},
};
module.exports = FtpController;
Best way to do stuff like this is probably a policy, since you'll want to be able to apply the check to various controllers as you build out your app. Here's what your policy might look like:
// policies/ftpAuthenticated.js
module.exports = function loginToFTP (req, res, next) {
if (req.session.ftpAuthenticated) {
// Onward!
next();
}
else {
// authenticate here (we assume it works in this example)
var success = true;
if (success) {
// Track that the user is connected via ftp for next time
req.session.ftpAuthenticated = true;
// save the connection object
req.session.ftp = theFTPConnectionThing;
next();
}
// if an error occurs, use the default error handler
else {
next( new Error('Sorry, an error occurred authenticating with FTP') );
}
}
}
I have the following code to insert data into DB - this code has to be executed in a sequential order
Router JS
module.exports = function(app) {
app.get('/registerUser', function(req, res ) {
objuser.userName = 'testuser';
objuser.password = 'password';
objuser.status = true;
registerUser (objuser ); //calls Business.js
res.OK();
res.end ();
});
}
Business.js
var registerUser = function (objuser )
{
userDB.registerUser (objuser ) ; //calls db.js
};
db.js
exports.registerUser = function (objUser )
{
var User = db.model(strCollectionName, UserSchema );
var objSchema = new User(objUser);
objSchema.save(function (err)
{
if (err)
console.error (err);
else
console.log ("registerUser : Data insertion success.");
});
}
In the db.js Im getting error from Mongo if I try to insert duplicate value. I wan to pass the error message to HTML page to display the same. What should I do? I tried
throw Error (err)
But it breaks the server.
Assuming you are using expressjs, I'd make use of the next callback. like so:
app.get('/registerUser', function (req, res, next) {
objuser.userName = 'testuser';
objuser.password = 'password';
objuser.status = true;
registerUser(objuser, function (err) {
if(err) {
//this will be handled by express's errorHandler or whatever you have configured
return next(err);
}
//do whatever you want to do with the response
});
});
If you don't want to make your Business.js call async then you will obviously change this code to a try...catch flow. Node.js apps are happier using async calls though, so a common convention in nodejs apps is to expose a callback using the (err, result) parameters. So your db.js call would be :
exports.registerUser = function (objUser, callback )
{
var User = db.model(strCollectionName, UserSchema );
var objSchema = new User(objUser);
objSchema.save(function (err) {
if (err) return callback(err);
return callback(null, objSchema);
});
}
By now you probably notice that your Business.js call would just be a mediator between your route and your db code...whether you need it or not is up to you.
HTH,
Mike
If you are using node.js >= 0.8.x you can use connect-domain middleware that adds new domain functionality to your express/connect application. With doamin module you don't need to pass error up manually. You can simple throw error and it will be passed to error handler automatically.