Good morning everyone, I have a question regarding the behavior of my firebase database.
I am populating an end point on my database user with multiple POST requests to my express server app.js from my client like so:
element.on("click", function(){
send request 1 - endpoint1
send request 2 - endpoint2
send request 3 - endpoint3
}
Then in my app.js I have handlers at the routes that use the Request package to make three seperate GET request to the Halo Waypoint API like so:
app.post(endpoint1, function(req,res){
request(HaloAPI + endpoint1, function(error, res, body){
[store data from the response body into an
object to be sent to firebase endpoint 'user']
// User's stats
database + "/user".set(dataObject)
}
}
app.post(endpoint2, function(req,res){
request(HaloAPI + endpoint2, function(error, res, body){
[store data from the response body into an
object to be sent to firebase endpoint 'user'.
This is a url for an image]
//This is a player's emblem
database + "/user/emblem".set(dataObject)
}
}
app.post(endpoint3, function(req,res){
request(HaloAPI + endpoint3, function(error, res, body){
[store data from the response body into an
object to be sent to firebase endpoint 'user'.
This is a url for an image]
//This is a player's Spartan portrait
database + "/user/spartanImage".set(dataObject)
}
}
I'm expecting the database to be updated all at the same time; however, that is not the case all the time. Usually when I click the button with the event listener attached endpoint 2 and 3 come in at the same time as the data from endpoint 1, but most of the time I only get data from only endpoint 2 or only endpoint 3. Eventually I stop getting the data from endpoint 2 and 3 all together. In fact, with this current setup I can see the endpoints user/emblem and user/spartanImage populate in the database console but then they are taken away as soon as they are added. This has been troubling me from the beginning of this project and I would really appreciate some insight from someone more experience in Firebase than myself. Below I will link my relevant code, thanks in advance for the help.
request.js is where the initial AJAX calls are made client-side:
$searchButton.on("click", function(event){
event.preventDefault();
// the value of the search field creates the request object
// it is just a user's Xbox Live Gamertag and is used for the
// the subsequent requests.
var $search = $("#searchField").val();
$.post(homeRoute + "statSearch", {search: $search}, function(data){
console.log(data)
});
firebase.database().ref().on("value", function(snapshot){
function ez(path){
return snapshot.child(path).val();
}
var dataObject = {
gamertag: ez("gamertag"),
totalKills: ez("totalKills"),
totalDeaths: ez("totalDeaths"),
totalGames: ez("totalGames")
};
console.log(dataObject)
});
$.post(homeRoute + "emblemSearch", {search: $search}, function(data){
console.log(data)
});
$.post(homeRoute + "spartanSearch", {search: $search}, function(data){
console.log(data)
});
From there we go over to app.js my express server to make GET requests to the Halo Waypoint API and send the response formatted with the data I want to firebase:
app.post("/statSearch", function(req, res){
var search = req.body.search;
var statsOptions = new Options("https://www.haloapi.com/stats/h5/servicerecords/warzone?players="+search);
request(statsOptions, function (error, response, body) {
if (error) throw new Error(error);
var body = JSON.parse(response.body)
var playerData = {
gamertag: body.Results[0].Id,
totalKills: body.Results[0].Result.WarzoneStat.TotalKills,
totalDeaths: body.Results[0].Result.WarzoneStat.TotalDeaths,
totalGames: body.Results[0].Result.WarzoneStat.TotalGamesCompleted
};
res.send(playerData)
var userRef = ref.child("user");
// sending off the data object to Firebase at the "user" endpoint
userRef.set(playerData);
});
});
//emblem
app.post("/emblemSearch", function(req, res){
var search = req.body.search;
var imgOptions = new Options('https://www.haloapi.com/profile/h5/profiles/'+search+'/emblem', '512');
request(imgOptions, function (error, response, body) {
if (error) throw new Error(error);
var imgString = response.request.uri.href;
res.send(imgString);
var emblemRef = ref.child("user/emblem");
// sending off the url to Firebase at the endpoint "user/emblem"
emblemRef.set(imgString);
});
});
//spartan image
app.post("/spartanSearch", function(req, res){
var search = req.body.search
var spartanOptions = new Options('https://www.haloapi.com/profile/h5/profiles/'+search+'/spartan', '256');
request(spartanOptions, function (error, response, body) {
if (error) throw new Error(error);
var imgString = response.request.uri.href;
res.send(imgString);
var spartanImage = ref.child("user/spartanImage");
// doing the same as emblem to this endpoint^^^^
spartanImage.set(imgString);
});
});
Related
I am working on a management system, currently creating the POST requests for the api. I need the values of the request's body to post a new city in the database. The values are used in the stored procedure as parameters. Instead of the key's values which I entered, I am getting an "undefined" value, sometimes a "[object Object]".
I am using a MySQL server, hosted in the cloud by Google's services. Backend is made with Node.js, routing with Express. None of my attempts to fix the bug worked for me.
What I've tried so far:
-Parsing each key's value .toString() and JSON.stingfify() from the body
-Converting the body to Json/string, then back to a javascript object
-Getting the response's requests's body (res.req.body)
-Getting the body's response values in an array, then pushing the next element after it has been passed as a parameter to the stored procedure
-Using the 'request' npm extension to put the values I need when calling the POST method.
-Changed the values to be stored in the URL' parameters instead of the body.
-Sent the body's values as form-data, JSON file, HTML page
Controller method in cityController.js:
exports.city_post = (req, res, next)=>{
poolDb.getConnection(function (err, connection){
if(!err) {
const sql = 'CALL createNewCity(?,?)';
var zipReq = req.params.zip;
var nameReq = req.params.name;
var reqBody = JSON.stringify(req.res.body);
connection.query(sql,[zipReq,nameReq], (err,rows)=>{
if(!err){
return res.status(201).json({Message: 'City with name: '+nameReq+' and zip code: '+zipReq+' created successfully\n', rows});
}
else{
return res.status(404).json({errorMessage: err})
}
});
}
else{
return res.status(500).json({errorMessage: "server error: "+this.err});
}
console.log("\nZip Code: "+ zipReq +"\nName: " + nameReq); //for testing
console.log("\nrequest body: " + reqBody); //for testing
});
}
City route:
const express = require('express');
const router = express.Router();
const CityController = require('../controllers/cityController.js');
router.get('/', CityController.city_getAll);
router.get('/:cityzip', CityController.city_getbyzip);
router.post('/add', CityController.city_post);
...
module.exports = router;
Expected: Posting a new field in table city, status code (201).
Actual: Status code (404), no new insertion in the DB. body, req.body.zip & req.body.name are of value "undefined".
Screenshots:
-Terminal output: https://imgur.com/a/brqKZlP
-Postman request: https://imgur.com/a/ZfFcX8Z
Express doesn't parse post body by default (for some reason). You can try popular body-parser npm package, or collect the raw body data and parse from a string yourself if you don't want to add a whole new package. Here as express app:
app.use(function(req, res, next){
var data = "";
req.on('data', function(chunk){ data += chunk})
req.on('end', function(){
req.rawBody = data;
var json = JSON.parse(req.rawBody); // assuming valid json. ideally check content-type first
next();
});
});
I created an ajax call to the IMBd database
// API Key
key = "4dba72b2-7558-4c0f-bd18-9ffcb0999c4e";
// Url
mainUrl = "http://api.myapifilms.com/imdb/top?token="+ key +"&format=json&data=0&start=1&end=250";
// API Call
var request = require('request');
request(mainUrl, function (error, response, body) {
if (!error && response.statusCode == 200) {
// Storing data in an object
var obj = JSON.parse(body), //JSON Parser
movieArray = obj.data.movies, //Creating Array
item = movieArray[randomMovieRank]; //Setting random movie variable
itermArray = [item.ranking,item.title,item.year];
console.log(itermArray);
io.sockets.emit("serverAnswer", {ranking: itermArray[0], title: itermArray[1], year: itermArray});
}
});
return false;
Followed up by:
socket.on("serverAnswer", function(data){
console.log(data.title);
});
The socket.on is called on the client side. The problem I am having is that it is pulling through the data very slowly if at all. The API is working as it is console logging correctly in terminal. But client side it sometimes pulls through ad sometimes doesnt. Is there something I am doing wrong?
EDIT:
Added pastebin: http://pastebin.com/TYHsqBmK
When you invoke the emit method, your client is not guaranteed connected,you can trigger the ajax event after the client connected or emit specified messages,such as
the server:
io.on('connection',function(socket){
if(movies !== null)
{
socket.emit("serverAnswer", {movies:movies});
}
else{
//1.ajax request IMDB resource
//2.set movies variables
//3.emit message
}
});
the client:
socket.on("serverAnswer", function(data){
console.log(data);
});
When I use jQuery ajax to retrieve data from nodejs (with express4), nodejs sends empty response back before data loaded from mongodb.
This is the message from nodejs console:
GET /query?uid=1 - - ms - -
And this is the error message from Chrome console:
GET http://192.168.1.105:3000/query?uid=1 net::ERR_EMPTY_RESPONSE
I can confirm that data are correctly loaded from mongodb because data can be printed on nodejs console after nodejs sent the empty response. And this is exactly the problem. Why nodejs sends reponse to client before data have been prepared?
I know nodejs is asynchronous and I pay much attention to this great feature, but I still have this problem.
This is my client code:
$.getJSON('/query', {uid:1}, function(response) { console.log('finished!'); });
And this is my server code:
var express = require('express');
var mongodb = require('mongodb');
var GeoJSON = require('geojson');
var strftime = require('strftime');
var router = express.Router();
var MongoClient = mongodb.MongoClient;
router.get('/query', function(req, res, next) {
var url = "mongodb://localhost/example_db";
var collection_name = "example_collection";
var poi = req.query.poi ? req.query.poi.split("||") : null;
var time = req.query.time;
var uid = req.query.uid;
var condition = {};
if (poi) condition.poiname = {$in: poi};
if (time) condition.checkin_time = {$gte:new Date(time.start_time), $lte:new Date(time.end_time)};
if (uid) condition.uid = parseInt(uid);
MongoClient.connect(url, function(err, db) {
if (err) console.log('connection error');
var collection = db.collection(collection_name);
collection.find(condition).sort({checkin_time:1}).toArray(function(err, result) {
if (err) {
console.log(err);
return res.send('error!');
}
if (!result) return res.send('no data');
//This line prints the result after empty response has been sent.
console.log(result);
var data = {};
data['geojson'] = GeoJSON.parse(result, {Point:'loc', include:['poiname', 'uid', 'checkin_time']});
res.json(data);
db.close();
});
});
My data are a little bit large, 12G stored in mongodb. So it usually takes about 3 minutes or more to complete the query. When I use findOne to retrieve only a single document, this is no problem.
Does the data size cause the problem?
Try GeoJSON.parse with callback
var data = {};
GeoJSON.parse(result, {Point:'loc', include:['poiname', 'uid', 'checkin_time']}, function (geojson) {
data['geojson'] = geojson;
res.json(data);
db.close();
});
Is there a way to use node module "request" multiple times in one route and have the results display on the same rendered ejs template page?
Goal: I want to display eBook information from the iTunes Store using their Search API. Right now I can get an ebook's price in one territory, but I would like to display prices for the same ebook in multiple countries. To get each different price, I need to use a different URL, either a default ending, "&country=gb", "&country=fr" etc. I can get prices for each of the 5 countries I am interested in, but I can't get them all on the same page. How can I construct my route and prepare my variables so that I can display information from all of these countries when I render one page?
I am using node, express and ejs, and I am making the http request using the "request" node module. Here are the basics of the form I'm using, where I enter the ISBN in the searchTerm field. (there's more, but it's bulky.)
<form action="/search">
<select name="searchTerm">
Code that is working now for getting info on the book in one territory:
app.get('/search', function(req, res){
var searchRequest = req.query.searchTerm;
var searchURL = "http://itunes.apple.com/lookup?isbn=" + searchRequest;
request(searchURL, function(error, response, body){
if (!error && response.statusCode == 200) {
var data = JSON.parse(body);
console.log(data.results[0]);
var iTunesResults = data.results[0];
res.render("test", {
iTunesResults: iTunesResults,
searchRequest: searchRequest
});
}
});
});
If I make a few changes in this code I can get information on the same ebook in a different country with just a few changes. Below is the code for great britain, and it works on its own, I just want to get results from both of these searches displaying at once, and I'm not sure where to begin.
app.get('/search', function(req, res){
var searchRequest = req.query.searchTerm;
var gbSearchURL = "http://itunes.apple.com/lookup?isbn=" + searchRequest + "&country=gb";
request(gbSearchURL, function(error, response, body){
if (!error && response.statusCode == 200) {
var data = JSON.parse(body);
console.log(data.results[0]);
var iTunesResults = data.results[0];
res.render("test", {
iTunesResults: iTunesResults,
searchRequest: searchRequest
});
}
});
});
What I want to do is make an additional request to Apple, using the same search term here but adding a country identifier to the end of the searchURL I'm passing into request. However, if I try to call request again and pass all of the results variables into res.render at once, the result of the first request will not be available inside the second request.("ReferenceError: iTunesResults is not defined")
I'm guessing there is a way to have an array of searchURL's and an array of results (req.query.searchTerm), then I can pass the array or a more complicated object in when I render the test.ejs template. Am limited to one http request per app.get route? (Forgive me if that should be obvious, but I just want to grab this pricing information and display it next to each other. Also, I figured it would be better to be verbose in my question.)
Ok! I got it resolved using the "async" node library. http://www.github.com/caolan/async
With that I can call multiple functions in parallel, and when they're done I can just pass back the results to a template to render.
app.get('/search', function(req, res){
async.parallel([
function(done){
var searchRequest = req.query.searchTerm;
var gbSearchURL = "http://itunes.apple.com/lookup?isbn=" + searchRequest + "&country=us";
request(gbSearchURL, function(error, response, body){
if (!error && response.statusCode == 200) {
// console.log(body)
var data = JSON.parse(body);
// below shows whole object of result 0
console.log(data.results[0]);
done(null, data.results[0]);
}
});
},
// UK pricing
function(done){
var searchRequest = req.query.searchTerm;
var gbSearchURL = "http://itunes.apple.com/lookup?isbn=" + searchRequest + "&country=gb";
request(gbSearchURL, function(error, response, body){
if (!error && response.statusCode == 200) {
// console.log(body)
var data = JSON.parse(body);
// below shows whole object of result 0
console.log(data.results[0]);
done(null, data.results[0]);
}
});
},function(err, iTunesResults){
res.render("test", {
iTunesResults: iTunesResults,
searchRequest: req.query.searchTerm
});
})
});
I'm developing a simple NODE.JS application. First I create an httpServer using http module. Then I route the request to the requestsHandlers.js page. 'Response' parameter cames from the creation of the httpServer. Process1, process2 and process3 should write an answer to the page. This is the objective of this app, that process1, process2 and process3 write its respective text.
requestHandlers.js
var process1 = require("./process1");
var process2 = require("./process2");
var process3 = require("./process3");
function iniciar(response) {
console.log("Manipulador de peticiĆ³n 'iniciar' fue llamado.");
response.writeHead(200, {"Content-Type": "text/html"});
process1.fc1(response);
process2.fc2(response);
process3.fc3(response);
//response.end() //WHERE DO I PLACE IT?
}
As you can see, the response parameter is passed to process1.js, which after parsing some data shoud echo some information.
process1.js
var request = require('request')
function fc1 (response){
var url = 'http://webpagethatreturnsJSONfile.com/'
//Download webpage data and parses it
request(url, function(err, resp, body) {
if (err)
throw err;
var jsonResult = JSON.parse(body);
response.write("Number:" + jsonResult.number + '');
//response.end() //WHERE DO I PLACE IT?
});
}
exports.fc1 = fc1;
The point is that I don't know where to put 'response.end()'. Each process takes some time and I want to 'end' when all processes have echo their text.
How could I do it?
I don't know if the code I've attached is enough for helping me.