I want to put my api in time out. I tried to put it in a "global" way when I create the server but the answer only says that no data was returned, not a 504 error. I also have the option to place it for each route, I think the time out should go in the controller of my app .
function initialize() {
return new Promise((resolve, reject) => {
const app = express();
httpServer = http.createServer(app);
app.use(morgan('combined'));
app.use('/proyecto', router_proyecto);
app.use('/tramitacion',router_tramitacion);
httpServer.listen(webServerConfig.port, err => {
if (err) {
reject(err);
return;
}
//httpServer.timeout = 500;
console.log('Servidor web escuchando en puerto:'+webServerConfig.port);
resolve();
});
});
}
exaple of a route:
router_proyecto.route('/getProyecto/:proyid?')
.get(proyecto.getProyecto);
Controller(Time out should go here):
async function getProyecto(req, res, next) {
try {
const context = {};
context.proyid = parseInt(req.params.proyid, 10);
const rows = await proyectos.getProyecto_BD(context);
if (rows.length >0) {
res.status(200).json(rows);
} else {
res.status(404).end();
}
} catch (err) {
next(err);
}
}
module.exports.getProyecto = getProyecto;
What does "time out" mean to you? Because a a timeout is a well defined term in Javascript and your server should definitely not be using that. If you want your server to simply serve some content with a specific HTTP code, depending on some global flag, then you were on the right track except you need to write it as middleware.
let lock = Date.now();
function serveLockContent(req, res, next) {
if (lock <= Date.now()) {
return next();
}
res.status(503).write('Server unavailable');
}
...
app.use(serveLockContent);
...
app.post('/lock/:seconds', verifyAuth, otherMiddlerware, (req, res) => {
lock = Date.now() + (parseInt(req.params.howlong) || 0) * 1000;
res.write('locked');
});
Related
I am using Node.js and express.js to build a website, and call APIs in my backend
But I got little bit confused on how to make my https request return strings at the same time,
because I also need it to return stringfy JSON data to Redis SETEX function
Here is my code down below
// I am sure this works just fine
function myweb(para1, para2, para3, res) {
https.get({
hostname: 'api.com',
path: '/search?q=' + para1 + '&offset=' + para2 + '&filter=' + para3,
headers: { 'Ocp-Apim-Subscription-Key': SUBSCRIPTION_KEY },
}, response => {
body = '';
response.on('data', part => {
body += part;
})
response.on('end', () => {
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify(JSON.parse(body)));
})
})
}
// And I got confused while trying to build up server cache
const redisPort = 6379;
const client = redis.createClient(redisPort);
app.get("/job", (req, res) => {
const aaa = `${req.query.q}`;
const bbb = `${req.query.offset}`;
const ccc = `${req.query.filter}`;
try {
client.get(aaa, async (err, jobs) => {
if (err) throw err;
if (jobs) {
return jobs;
} else {
const jobs = myweb(aaa, bbb, ccc, res);
client.setex(aaa, 600, JSON.stringify(jobs));
}
});
} catch(err) {
res.status(500).send({message: err.message});
}
});
My logs told me that I try to give a undefined in third parameter of client.setex (which is JSON.stringify(jobs) )
But no matter I try, I just can't make my function myweb to return a proper value to SETEX...?
I think I might have some misunderstandings on https request but I am not sure...?
Please help... Thank you!
Redis saves values as strings. You need to parse the result when reading from it.
client.get(aaa, async (err, jobs) => {
if (err) throw err;
if (jobs) {
return JSON.parse(jobs);
} else {
const jobs = myweb(aaa, bbb, ccc, res)
client.setex(aaa, 600, JSON.stringify(jobs));
}
});
The async function below is supposed to check if a url is a legit url
let CheckUrl = function (url, done) {
dns.lookup(url, function(err, address) {
if (err) return done(err);
done(null, true); //return true because I don't care what the address is, only that it works
});
}
The express.js code below gets the url but I'm having trouble understanding how to write the if statement so that it returns true or false.
// Gets URL
app.post("/api/shorturl/new", function(req, res) {
if (CheckUrl(req.body.url)) {
// do something
}
});
I'm not sure what to pass as the second argument in CheckUrl() in this if statement. Or maybe I wrote the first async function incorrectly to begin with?
Please use the async await
I have written a test code for you as below:
const express = require('express');
const app = express();
const dns = require('dns');
let CheckUrl = function (url, done) {
return new Promise((resolve, reject) => {
dns.lookup(url, function(err, address) {
console.log("err " , err)
if (err) {
resolve(false)
} else {
resolve(true)
}
});
});
}
app.post("/api/shorturl/new", async function(req, res) {
try {
let result = await CheckUrl(req.body.url);
console.log("result " , result)
res.send(result)
}
catch (error) {
console.log("in catch error " , error)
res.send(error)
}
});
app.listen(3000)
you can get the knowledge to know about the Promise here. The Promise object represents the eventual completion (or failure) of an asynchronous operation and its resulting value.
As mentioned by DeepKakkar, this was what I was looking for:
app.post("/api/shorturl/new", async (req, res) => {
try {
let result = await CheckUrl(req.body.url);
res.send(result)
}
catch (error) {
return new Error('Could not receive post');
}
});
I run node app with CORS.
Currently I load whitelisted domains from .env file but I need to change it to load them from database. The whole CORS functionality is synchronous and I wonder what's the proper way to make db query for it.
app.js
app.use(cors());
async function listenCallback(server) {
try {
// app code
} catch (err) {
server.close();
}
cors.js
const cors = require('cors');
const db = require('../db');
const whitelist = db.raw('select domains from table'); // I need to change this
module.exports = (enabled = true) =>
(req, res, next) => {
const options = {
origin(origin, callback) {
if (!origin) {
callback(null, true);
return;
}
const originIsWhitelisted = enabled ? whitelist.indexOf(origin) !== -1 : true;
if (originIsWhitelisted) {
callback(null, originIsWhitelisted);
return;
}
callback({
statusCode: 401,
error: 'Not allowed',
});
},
};
return cors(options)(req, res, next);
};
If what you're trying to do is to load a set of domains from a database upon module initialization so you can then use those in some middleware, then you can get a promise from loading the whilelist from the database and then just use that promise in your middleware.
const cors = require('cors');
const db = require('../db');
const whitelistPromise = db.someOperationThatReturnsPromise();
module.exports = (enabled = true) =>
(req, res, next) => {
const options = {
origin(origin, callback) {
if (!origin) {
callback(null, true);
return;
}
whitelistPromise.then(whitelist => {
const originIsWhitelisted = enabled ? whitelist.indexOf(origin) !== -1 : true;
if (originIsWhitelisted) {
callback(null, originIsWhitelisted);
return;
}
callback({
statusCode: 401,
error: 'Not allowed',
});
}).catch(err => {
console.log(err);
next(err);
return;
});
},
};
return cors(options)(req, res, next);
};
Another approach is to export a module constructor function from the module that returns a promise that tells your server when your module initialization is done and provides this middleware function as the resolved value. I like this approach better because if the db operation fails, you will know it more centrally and can provide better error handling.
const cors = require('cors');
const db = require('../db');
// export module constructor that initializes this module asynchronously and returns a promise
// That promise resolves to the middleware function (so it can't be used before
// the module is properly initialized)
module.exports = function() {
return db.someOperationThatReturnsPromise().then(whitelist => {
return (enabled = true) => (req, res, next) => {
const options = {
origin(origin, callback) {
if (!origin) {
callback(null, true);
return;
}
const originIsWhitelisted = enabled ? whitelist.indexOf(origin) !== -1 : true;
if (originIsWhitelisted) {
callback(null, originIsWhitelisted);
return;
}
callback({
statusCode: 401,
error: 'Not allowed',
});
},
};
return cors(options)(req, res, next);
};
});
}
In this case, whoever loads this module will do it something like this:
require('./myModule')().then(makeWhitelistMiddleware => {
// put route handlers here that use the function to make CORS middleware
// don't start your server until this completes
app.use(makeWhitelistMiddleware());
// other routes here
app.get(...)
// start server
app.listen(...);
}).catch(err => {
console.log("Could not initialize myModule");
process.exit(1);
});
Lastly, I'll add that there is effort underway to allow top level await inside of module initialization where the whole module loader system can be made aware of promises involved in initializing a module. That type of capability would make this a lot simpler, but until then you have to add your own custom code to initialize the module differently and load the module differently.
I use koa, domain and koa-respond.
I use domain because request sometime crashes and I want to not crash node.js.
My question is, is it possible to cancel request from node.js domain? I want to cancel request and show a response for user.
The below code hangs the request but not sending response (though node.js is not crashed):
const domain = require('domain');
export default {
tryReq: async (ctx, next) => {
try {
const d = domain.create();
const parsedData = await d.run(async () => {
const MyLink = `http://thesite.com/${ctx.params.data}`;
d.add(ctx);
d.on('error', err => {
try {
ctx.throw(403, 'Crashing');
d.dispose();
} catch (er) {
console.error('Error', er, ctx.params.data);
d.dispose();
}
});
const parsedDataValue = await callUrl(MyLink);
return parsedDataValue;
});
return ctx.ok(parsedData);
} catch (err) {
ctx.internalServerError(err);
}
}
};
I'm trying to test what happens when the user destroy callback receives an error for the user controller. When destroy receives an error, it does the following:
flash('error', 'Can not destroy user');
redirect(path_to.users);
This is the test so far:
it('should fail on DELETE /users/:id if destroy receives an error', function (done) {
var User = app.models.User;
var user = new UserStub();
User.find = sinon.spy(function (id, callback) {
callback(null, user);
});
user.destroy = sinon.spy(function (callback) {
callback(new Error());
});
request(app)
.del('/users/55')
.end(function (err, res) {
res.header.location.should.include('/users');
app.didFlash('error').should.be.true;
done();
});
});
I've seen this question and the res.header.. portion works as expected. However, I'm still confused on how I can test the flash that happens after that redirect.
I ended up changing the users_controller to use the following code for a destroy callback (the redirect was having other issues):
if (error) {
flash('error', 'Can not destroy user');
} else {
flash('info', 'User successfully removed');
}
send(302, "'" + pathTo.users + "'");
The init.js file used with mocha.js has a few pieces in it when initializing the app object (some irrelevant code was omitted):
global.getApp = function(done) {
var app = require('compound').createServer();
app.renderedViews = [];
app.flashedMessages = {};
app._render = app.render;
app.render = function (viewName, opts, fn) {
app.renderedViews.push(viewName);
// Deep-copy flash messages
var flashes = opts.request.session.flash;
for(var type in flashes) {
app.flashedMessages[type] = [];
for(var i in flashes[type]) {
app.flashedMessages[type].push(flashes[type][i]);
}
}
return app._render.apply(this, arguments);
};
app.use(function (req, res, next) {
app._request = req;
next();
});
app.didFlash = function (type) {
var flashes = app._request.session.flash;
return !!(app.flashedMessages[type] || (flashes && flashes[type]));
};
return app;
};
The original way of checking for didFlash was limited to only rendering, but this checks if a flash message is created before a redirect or send.