I am trying to grasp using node express server and jQuery.ajax() in tandem. I have created a code repository with the following structure:
/
|-public
| |-index.html
|-server.js
My index page has the following JS snippet in it:
var successHandler = function (data, status, jqXHR) {
console.log('success')
};
var failHandler = function (jqXHR, status, errorThrown) {
console.log('fail')
};
var progressHandler = function () {
console.log('progress')
};
var ajaxConfig = {
url: 'http://localhost:4444/test',
type: 'GET'
};
$.ajax(ajaxConfig).then(successHandler, failHandler, progressHandler);
the server-side code is defined as such:
const express = require('express')
const app = express()
const sleep = require('sleep')
app.get('/test', function (req, res) {
console.log('/test method called!');
sleep.sleep(3);
res.status(202).send({"thing":"stuff"})
})
app.post('/test', function(req,res){
res.status(202).send('ok')
})
app.use(express.static('public'))
app.use(express.static('node_modules/jquery/dist'))
app.listen(4444, function () {
console.log('Running on localhost:4444!')
})
The thing that I want to accomplish is to get some hits on the progress handler, just to get it to write data in the console.
According to this page, I need to use the deffered.notify() method to trigger the handler but I have no idea how to get to the deffered object. I tried saving the return value of $.ajax() but that doesn't seem to have the notify() method since it is a jqXHR object.
It is my understanding that I need to have a progress handler defined on the server-side (the post handler for the /test route) that gets called to get to the current status of the pending task. Don't think making a new ajax request is the way to go, but I might be wrong. I have also found some articles that utilize the setTimeout method, My guess is that it gets used in order to repeatedly call the endpoint that gives status info.
Related
As a follow up to the this post:
mongoose find all not sending callback
I am trying now to send a Object along with a page in my nodejs/expressjs app instead of sending the JSON data as the response only.
The route for my page
//Get latest listings page
router.get('/latest', function (req, res) {
var rL = Request.getAllRequestListingsCb();
res.render('latest');
});
And as per the linked post, it suggest the following below but I need to return a JSON to my route, not send it direct to the client.
//Find all.
module.exports.getAllRequestListings = function (response) {
var query = {};
Request.find(query, function (err, docs) {
response.send(docs);
});
};
Have attempted to use a promise but my rL var keep returning as undefined so the Promise never gets get as "done" and i believe to be because I have not changed it correctly so now am here.
(The end goal is to render a table within the latest page using "handlebars" to display the data from the Json send with the page.)
You should be using proper callback chaining as find method is asynchronous.
//Find all.
module.exports.getAllRequestListings = function (callback) {
var query = {};
Request.find(query, callback);
};
Router
//Get latest listings page
router.get('/latest', function (req, res) {
Request.getAllRequestListingsCb(function (err, docs){
res.render('latest', { rL: docs });
});
});
I want to use flickrapi (https://www.npmjs.com/package/flickrapi) package. I need to authorize it:
Flickr.tokenOnly(flickrOptions, function(error, flickr) {
//I need this flickr variable
});
and I want to use this flickr variable in my express code
app.get('/', function (req, res) {
//do something with flickr
});
How should I do it?
Modular approach:
Put your flickr connectivity code separate:
flickr-public.js
var Flickr = require("flickrapi"),
flickrOptions = {
api_key: "API key that you get from Flickr",
secret: "API key secret that you get from Flickr"
};
module.exports = (function(){
Flickr.tokenOnly(flickrOptions, function(error, flickr) {
//handle error here
console.log('Flickr Object Obtained');
return flickr;
});
})();
Note: Better instantiate the flickr object in your app.js file.
So that the object gets created immediately when server starts. As this flickr object is for public API only and does not need authentication again and again.
You can instantiate the flickr object by simply requiring it in app.js file:
require('./flickr-public');
Now Simply access flickr object anywhere by simply requiring it.
routes.js
const flickr = require('../path-to/flickr-public');
app.get('/', function (req, res) {
//use flickr object to perform actions.
});
Explanation:
From the node.js documentation:
Modules are cached after the first time they are loaded. This means (among other things) that every call to require('foo') will get exactly the same object returned, if it would resolve to the same file.
Multiple calls to require('foo') may not cause the module code to be executed multiple times.
Just put it inside your get
app.get('/', function (req, res) {
Flickr.tokenOnly(flickrOptions, function(error, flickr) {
//do something res.status(200).send('what you want here');
});
});
use it directly inside your route callback
app.get('/', function (req, res) {
Flickr.tokenOnly(flickrOptions, function(error, flickr) {
//call someother method to get photos etc. and finally call res.send()
res.send(photos); // where photos is obtained from flickr or anything you can pass which should be response of you request.
});
});
I am using nodejs express framework for my development. The web page has two buttons
1) Submit which calls the following function:
router.get('/record_enrich_quick/:quick', function(req, res) {
console.trace();
var json_struct={};
json_struct["start_time"]=req.params.quick;
json_struct["end_time"]="now";
json_struct["cookie"]=Math.random().toString();
var data=JSON.stringify(json_struct);
var args={
data:data,
headers: { "Content-Type": "application/json" }
}
//var Rest = require('node-rest-client').Client;
//var client=new Rest();
de_rest_client.post("http://localhost:8080/recordenrich",args,function(data,response){
console.log("Received response from data enrich start");
});
});
2) Refresh which calls the following function
router.get('/getDataEnrich/:from', function(req, res, next) {
var fromValue = req.params.from;
//Calls Elasticsearch and gets the data from it .
});
Issue:
When I click on submit a REST calls goes and it repeats again and again.
No way this call has gone from the front end ie: HTML. The reason is that I can't find the call on the Network side of the developer tools.
Also I have a debug point on the HTML side javascript where the function for "/record_enrich_quick/:quick" gets called, on the second time the debugger does not even point here. Which means there is some other place from where this function gets called multiple times.
To Summarize:
My function which has a rest call is called multiple times while the button which calls this function is pressed only once.
Is it something related to nodejs event queues? I am not sure.
I finally found out the reason
My submit part of the code didnt have response .end .Below code solved my issue .Lesson was we cant keep a request hanging
router.get('/record_enrich_quick/:quick', function(req, res) {
console.trace();
var json_struct={};
json_struct["start_time"]=req.params.quick;
json_struct["end_time"]="now";
json_struct["cookie"]=Math.random().toString();
var data=JSON.stringify(json_struct);
var args={
data:data,
headers: { "Content-Type": "application/json" }
}
//var Rest = require('node-rest-client').Client;
//var client=new Rest();
de_rest_client.post("http://localhost:8080/recordenrich",args,function(data,response){
res.end("reqest ends ");//This is was what made everything work
});
});
I have a NodeJS/Express web application that allows the user to upload a file, which I then parse using connect-busboy save to my database using Sequelize. Once that's done, I want to redirect the user to a given page. But Express is returning a status of 404 before my Promise resolves, even though I'm never calling next(), which I thought was mandatory in order to call the next handler in the middleware chain and thus result in a 404.
This is my code so far:
function uploadFormFile(req, res, next) {
var documentInstanceID = req.params.documentInstanceID;
// set up an object to hold my data
var data = {
file: null,
documentDate: null,
mimeType: null
};
// call the busboy middleware explicitly
// EDIT: this turned out to be the problem... of course this calls next()
// removing this line and moving it to an app.use() made everything work as expected
busboy(req, res, next);
req.pipe(req.busboy);
req.busboy.on('file', function (fieldName, file, fileName, encoding, mimeType) {
var fileData = [];
data.mimeType = mimeType;
file.on('data', function (chunk) {
fileData.push(chunk);
});
file.on('end', function () {
data.file = Buffer.concat(fileData);
});
});
req.busboy.on('finish', function () {
// api methods return promises from Sequelize
api.querySingle('DocumentInstance', ['Definition'], null, { DocumentInstanceID: documentInstanceID })
.then(function (documentInstance) {
documentInstance.RawFileData = data.file;
documentInstance.FileMimeType = data.mimeType;
// chaining promise
return api.save(documentInstance);
}).then(function () {
res.redirect('/app/page');
});
});
}
I can confirm that my data is being persisted correctly. But due to the race condition, the web page says 'can't POST' due to the 404 status being returned by Express, and the res.redirect is failing with an error setting the headers because it's trying to redirect after the 404 has been sent.
Can anyone help me figure out why Express is returning the 404?
The problem is coming from your internal call to busboy inside your handler. Rather than it executing and simply returning control to your handler, it would be calling the next which is passed to it before it returns control. So you code after the busboy call does execute, but the request has already advanced past that point.
In cases in which you want some middleware to only be executed for certain requests, you can chain middleware into those requests, such as:
router.post('/upload',busboy,uploadFromFile)
You can also separate them with .use() such as:
router.use('/upload', busboy);
router.post('/upload', uploadFromFile);
Either of the above will chain the middleware in the way you intended. In the case of .use() the middleware would also be applied to any applicable .METHOD() as Express refers to it in their documentation.
Also, note that you can pass in an arbitrary number of middleware this way, either as separate parameters or as arrays of middleware functions, such as:
router.post('/example', preflightCheck, logSomeStuff, theMainHandler);
// or
router.post('example', [ preflightCheck,logSomeStuff ], theMainHandler);
The execution behavior of either of the above examples will be equivalent. Speaking only for myself and not suggesting it is a best practice, I normally only use the array-based addition of middleware if i am building the middleware list at runtime.
Good luck with it. I hope you enjoy using Express as much as I have.
I'm new to node.js but I know somewhat about socketstream web framework by using this I can easily call a server side node.js method from JavaScript. I don't know how to do this without using that framework. How can I call the node.js method from JavaScript?
The below code is using socketstream to call server side method. So I want to call the same server side method without using this framework.
ss.rpc('FileName.methodName',function(res){
alert(res);
});
I'd suggest use Socket.IO
Server-side code
var io = require('socket.io').listen(80); // initiate socket.io server
io.sockets.on('connection', function (socket) {
socket.emit('news', { hello: 'world' }); // Send data to client
// wait for the event raised by the client
socket.on('my other event', function (data) {
console.log(data);
});
});
and client-side
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('http://localhost'); // connec to server
socket.on('news', function (data) { // listen to news event raised by the server
console.log(data);
socket.emit('my other event', { my: 'data' }); // raise an event on the server
});
</script>
Alternatively, you can use a router function which calls some function on specific request from the client
var server = connect()
.use(function (req, res, next) {
var query;
var url_parts = url.parse(req.url, true);
query = url_parts.query;
if (req.method == 'GET') {
switch (url_parts.pathname) {
case '/somepath':
// do something
call_some_fn()
res.end();
break;
}
}
})
.listen(8080);
And fire AJAX request using JQuery
$.ajax({
type: 'get',
url: '/somepath',
success: function (data) {
// use data
}
})
Not exaclty sockets but a simple solution:
Can I suggest trying api-mount. It basically allows calling API as simple functions without having to think about AJAX requests, fetch, express, etc. Basically in server you do:
const ApiMount = apiMountFactory()
ApiMount.exposeApi(api)
"api" is basically an object of methods/functions that you are willing to call from your web application.
On the web application you then do this:
const api = mountApi({baseUrl: 'http://your-server.com:3000'})
Having done that you can call your API simply like this:
const result = await api.yourApiMethod()
Try it out. Hope it helps.