Angular with hapi js server jsonp - javascript

I have an endpoint defined at /api/profile which accepts post parameters.
var http = require('http');
var serverConfig = require('../server.config.js');
var request = require('request');
module.exports = function(server){
server.route({
method: 'POST',
path: '/api/profile',
handler: getProfileData
});
function getProfileData(request, reply){
var battleTag = request.payload.battleTag;
getProfileDataHttp(battleTag, function(err, data){
if(err){
reply(new Error(err));
}
reply(data);
});
}
function getProfileDataHttp(battleTag, callback){
var key = serverConfig.battleNet.apiKey;
var tag = encodeURIComponent(battleTag);
var url = 'https://eu.api.battle.net/d3/profile/'+ tag + '/?locale=en_GB&callback=JSON_CALLBACK&apikey=' + key;
console.log(url);
request(url,function(error, response, body){
if(error){
callback(err);
}
if(!error && response.statusCode ==200){
callback(null, body);
}
});
}
};
it is calling an api with a json callback, when I am receiving the data it is in format:
JSON_CALLBACK({ json data here})
how can I get this endpoint to return just the json data, I have tried JSON.parse() but it causes errors in the server.
the angular service that calls this endpoint is like below:
function getProfileData(battleTag){
var defer = $q.defer();
var tag = validTag(battleTag);
if(!tag){
defer.reject('Invalid Tag please use format 1[a-z]11[a-z0-9]#4[0-9]');
return defer.promise;
}
$http.post('/api/profile', {
battleTag: battleTag
})
.success(function(data){
if(data.reason){
defer.resolve(data.reason);
}
defer.resolve(data);
})
.error(function(err){
defer.reject(err);
});
return defer.promise;
}
the call would work when using $http.jsonp in angular however I had to create the server to hide the secret key from the client

Your question is a bit confusing. You are talking about JSONP, but you want to fetch the data directly.
The whole point of JSONP is to return the data encapsulated inside a function that you choose. You then simply have to execute it.
If you want the data in a direct way, don't use JSONP. Simply do a "normal" call.
After having a quick look at the Battle.net API, it seems that to get the data directly, you should simply omit the 'callback' parameter in the URL of your request.
Thus, your request URL would looks like that:
var url = 'https://eu.api.battle.net/d3/profile/'+ tag + '/?locale=en_GB&apikey=' + key;

Related

Sending data from NodeJS to the client by using Ajax calls

I increase a value at the server by running an Ajax call and want to update my UI after doing this
function increaseHitpoints(){
$.ajax({
type: 'GET',
url: 'http://localhost:8888/incHp/2312'
}).done(function (data) {
$("#txtHitpoints").html(data);
});
}
In my app.js I read a JSON file, manipulate the value, write it back to the file and return it to the client
app.get('/incHp/:id', function (req, res) {
var database = './database.json';
fs.readFile(database, 'utf8', function (err, data) { // read the data
var json = JSON.parse(data);
var users = json.users;
var hitpoints;
users.find(u => {
if (u.id === Number(req.params.id)) { // get the user by id
u.hitpoints++;
hitpoints = u.hitpoints;
}
});
json = JSON.stringify(json);
fs.writeFile(database, json, (err) => { // update the JSON file
// -> missing part here <-
});
});
});
what do I have to pass into the missing part if I want to return the new value? The new value would be hitpoints
I tried res.send(hitpoints); but it seems this function wants to return a status code, not a value.
If you send a numerical value, it will be observed as an HTTP response code
https://expressjs.com/en/api.html#res
But you can send your hitpoints as a string res.send(hitpoints.toString())or as json res.send({hits: hitpoints});
Depends on what format you want your response to be. I prefer using JSON. So in JSON case you would do this:
fs.writeFile(database, json, (err) => {
res.status(200).json({yourKey: yourValue});
});
Then you can access the JSON object in your frontend:
$("#txtHitpoints").html(data.yourKey);

Pass data from one js file to other synchronously in NodeJS

I have a situation where I need to service function in service folder from my controller folder and once I receive the output I need to pass it back to UI.
//controller
var service = require('service');
api.get('/users', function(request, response) {
var name = request.query['name'];
var responseFromService = service.someAPI(name);
response.send(responseFromService).status(200);
});
//Service
exports.callTwitterAPI = function(twitterHandle,callback){
var responseFromTwitterService;
console.log("Calling Twitter API.." + twitterHandle);
someAPI.get('users/show', {screen_name: twitterHandle}, function (err, data, res) {
if (err) {
//loggerError.error('No connection to twitter :', Date.now());
responseFromTwitterService = JSON.stringify(err) + "Unable to connect twitter";
} else if (data.errors) {
responseFromTwitterService ="User Not Found!!"
// loggerInfo.info('No Twitter handle found for :', twitterHandle);
} else {
console.log("here..");
responseFromTwitterService = data;
}
console.log('response : '+ responseFromTwitterService);
return (null,responseFromTwitterService);
});
}
Now, I need to hold execution of
response.send(responseFromService).status(200);
this line until my service returns response, I need to make it synchronous.
Thanks in advance :)
Your service is going to either be synchronous by nature, or asynchronous by nature, and how you handle it will be determined by that.
If the service call is synchronous, then what you've written will work fine. If it's asynchronous, then you'll just need to send your response in its callback, e.g.:
//controller
var service = require('service');
api.get('/users', function(request, response) {
var name = request.query['name'];
var responseFromService = service.someAPI(name, function(err, responseFromService) {
response.send(responseFromService).status(200);
});
});
//Service
exports.someAPI = function(name, callback){
//some calculations
return callback(null, responseFromService);
}
EDIT after your update
Your service is never calling the callback you declared. Note your last line:
return (null, responseFromTwitterService);
Doesn't actually do anything. Instead you want:
return callback(null, responseFromTwitterService);
And then your calling code in the controller can be written as I suggested.

Is there a way to get the response for a specific emit using socket.io?

I need to perform GET requests on a server that doesn't have a CORS header, so I created a very simple node app that will do the GET for me:
var io = require('socket.io')();
var request = require('request');
io.on('connection', function(socket) {
socket.on('get', function(url) {
request(url, function(error, response, body) {
socket.emit('response', body);
});
});
});
On the client side, I'm using it with a simple get function:
var socket = io();
function get(url) {
return new Promise(function(resolve) {
socket.emit('get', url);
socket.once('response', function(data) {
resolve(data);
});
}
}
This works great when I request a URL one at a time:
get('http://some/resource/1');
But when I try multiple requests to different endpoints at the same time, they will all return the same data:
get('http://some/resource/1');
get('http://some/resource/2');
get('http://some/resource/3');
In this case, the data for /resource/1 is returned for all 3. I understand that this is because the socket.once('response') callback is getting added immediately for all 3 requests, and when the data is returned for the first one, all 3 callbacks are invoked for it.
Is there a way that I can get it so that each socket.emit() and socket.on() are paired to each other? I know that I can add a unique ID to each emit and pass it back on the response, or use the unique ID in the message itself (something like socket.emit('get:a54jk14hf'), but I'm hoping for a simpler solution if there is one.
The issue is that you are overwriting the socket.io's "response" event by issuing the "once" hook inside the "get" function. It's fine to keep it in there, but you'll need to provide a unique event for "once", that way four unique events will come back. This could be done using the "url" as key. It would look something like this:
Server:
var io = require('socket.io')();
var request = require('request');
io.on('connection', function(socket) {
socket.on('get', function(url) {
request(url, function(error, response, body) {
socket.emit(
'response-' + url, // USING THIS INSTEAD OF JUST "response"
body
);
});
});
});
Client:
var socket = io();
function get(url) {
return new Promise(function(resolve) {
socket.emit('get', url);
socket.once(
'response-' + url, // USING THIS INSTEAD OF JUST "response"
function(data) {
resolve(data);
});
}
}
I'm not sure if this was a requirement of yours, but the above approach would also enable you to have the correct data always come back to the Promise's "then" block.
get('http://some/resource/1').then(function (data) {
// the "data" is now guaranteed to be from resource "1"
// previous, it could have been from 1, 2, or 3
})

Meteor HTTP.call undefined on Client-side, working on Server-side

I am currently trying to learn how to do HTTP requests in Meteor. When I run the code, I can properly see the data in the console. However, on the client side all I get is "undefined". I believe I'm running the HTTP.get method synchronously.
.JS file
if (Meteor.isClient) {
Template.test.helpers({
testGET: function(){
var origin = Meteor.call('fetchFromService');
console.log(origin); //-- Displays 'Undefined'
}
});
}
if (Meteor.isServer) {
Meteor.methods({
fetchFromService: function() {
this.unblock();
var url = "https://httpbin.org/get";
var result;
try{
result = HTTP.get( url );
} catch(e) {
result = "false";
}
console.log(result.data.origin); //-- Displays the data properly
return result.data.origin;
}
});
}
It's async, you have to pass a callback to the call function:
var origin = Meteor.call('fetchFromService', function(err, data) {
console.log(data);
});
If you don't pass the callback, origin will be undefined until the request finishes.

Node Express pass variable from client to server

I am trying to return value from an input box to a variable in route, by taking this source as a reference but am stuck, in the example author is searching a keyword, constructing a url using this keyword, and returning a body response.
My use case is a little different I need user to provide a url as a string in search box, which I would then pass to my request function to spit response body
Current app.js (server-side)
app.get('/searching', function(req, res){
// input value from search
var url = req.query.search;
console.log(url); // prints value
request({ uri: url}, function (error, response, body) {
if (!error) {
content = body;
console.log(content);
} else {
console.log('Oops! Error when contacting slack.com');
}
});
res.send(content);
});
main.js (client-side)
$(function(){
$('#submit').on( 'click', function () {
var sSearch = $('#search').val();
var parameters = { search: sSearch };
$.get( '/searching',parameters, function(data) {
$('#results').html(data);
});
});
});
I realize /searching in both above files must be replaced because currently its trying to 'search' the user entered url value as a query string, so if I enter "https://google.com" in the text box the application tries to search:
http://localhost:3000/searching?search=https%3A%2F%2Fgoogle.com
instead I need it to pass this url as is to the request function so that I can print the body response, which in this case would be the page's source code. But am not sure how should I proceed
index.jade (template)
extends layout
block content
input#search(type="search", placeholder="Enter Keyword")
button#submit(type='submit',class='btn btn-success') Search
h2#results
script(src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.3/jquery.min.js")
script(src="/javascripts/main.js")
How should I format so that I can pass the variable from client to server and then send it back to client after processing? Any help is appreciated.
In the app.js you are making a async http call, but the response is sent before the http callback is invoked. Just move the res.send(content); inside the call back
app.get('/searching', function(req, res){
// input value from search
var url = req.query.search;
console.log(url); // prints value
request({ uri: url}, function (error, response, body) {
if (!error) {
content = body;
console.log(content);
} else {
console.log('Oops! Error when contacting slack.com');
}
res.send(content);
});
});
i see ajax request in your client code , so in your server code, try to response something like this :
res.status(200).json(content)
in your client code ,check if the content is there (console.log(data) before $().html(data)... )
PD : request is async , so you have to response inside request callback.

Categories