Finally diving into meteor. I have a small problem regarding http get requests.
On the client a simple call is executed to get data from the server.
if (Meteor.isClient) {
Template.liveprice.helpers({
price: function() {
Meteor.call('getPrice', function(error, response) {
if (error) {
return error;
} else {
return response;
}
})
}
})
}
On the server data is retrieved from a live and public API. It works fine on the server, but an undefined result is send back to the client. What am I missing here?
if (Meteor.isServer) {
Meteor.methods({
getPrice: function() {
var url = 'https://www.bitstamp.net/api/ticker/';
var req = HTTP.call('GET',url,function(error, result) {
//console.log(result);
if (result.statusCode == 200) {
var last = result.data.last;
console.log(last);//this shows the desired result in the server's console
return last;//sends back undefined to the client
} else {
return error;
}
});
}
})
}
#epascarello is right. Luckily, Meteor's HTTP works synchronously as well thanks to fibers. Try this:
Meteor.methods({
getPrice: function() {
var url = 'https://www.bitstamp.net/api/ticker/';
var result;
try {
result = HTTP.get(url);
check(result.data.last, String);
return result.data.last;
} catch (error) {
throw new Meteor.Error('get-price-failed', 'Could not retrieve the price.');
}
}
});
Related
I am trying to achieve a url preview for my Meteor + React app, where when users paste in a url in a textarea, they'll get a preview of the url. I plan to achieve this by using several npm modules i.e.:
url-regex, and
open-graph-scraper
I understand that in order to avoid any CORS issue, the request should be done server side.
So I have this currently set up:
//on client
import urlRegex from 'url-regex';
const onTextareaChange = e => {
let value = e.target.value;
let testURL = urlRegex().test(value) //returns true if url exists in textarea
console.log(testURL);
if(testURL){
let extractURL = value.match(urlRegex()) //extract the url
extractURL.map(url =>{
console.log(url)
Meteor.call('scrapeURL',{url}, function (result){
console.log(result)
})
})
}
/* console.log(e.target.value) */
setTextarea(e.target.value)
}
//on server
import ogs from 'open-graph-scraper';
/* 24. scrapeURL */
'scrapeURL' ({url}){
new SimpleSchema({
url : { type : String }
}).validate({url})
if(!Meteor.userId){
throw new Meteor.Error('not-authorised!')
} else {
let options = { 'url': url };
ogs(options)
.then(function (result) {
console.log('result:', result);
return result;
})
.catch(function (error) {
console.log('error:', error);
});
}
}
The problem here is, when i tried to console.log the results on the server, the scraped data shows up in the server console. but when i tried to return the results from the server to client, console.log on the client shows undefined.
I haven't got a clue what's wrong with the code.
Your scrapeUrl function doesn't return any data (you only described what the .then() function will return), you should try this way :
import ogs from 'open-graph-scraper';
/* 24. scrapeURL */
'scrapeURL' ({url}){
new SimpleSchema({
url : { type : String }
}).validate({url})
if(!Meteor.userId){
throw new Meteor.Error('not-authorised!')
} else {
let options = { 'url': url };
// here return the full promise :
return ogs(options)
.then(function (result) {
console.log('result:', result);
return result;
})
.catch(function (error) {
console.log('error:', error);
// probably here a need to tell the client that there was an error
//throw new Meteor.Error(error);
});
}
}
Here is a good reading on medium about the use of promises in Meteor :
https://blog.meteor.com/using-promises-and-async-await-in-meteor-8f6f4a04f998
I am trying to retrieve the access token from an API (https://github.com/Axosoft/node-axosoft/)
To receive an access token we have to follow this process:
var axo = nodeAxosoft(axosoftUrl, credentials);
axo.Api.getLoginUrl(function(url) {
// open browser using authorizationUrl and get code parameter from
//redirected Url after login
var code = 'code received from redirect';
axo.Api.exchangeCodeForToken(code);
});
As I did not understood exactly how to get the code following that example nor what is the url parameter on getLoginUrl, I did it on my own.
I have a login route that redirects the user to the axosoft website for authentication and redirects the user to the /authorization-process route on my application.
On the /authorization-process I get the code returned by the login and call a function that should get the access token by calling:
axo.Api.exchangeCodeForToken(code);
Code:
var axosoft_code = req.query.code;
console.log(axosoft_code);
var token = request.exchangeAuthCodeForAccessToken(axosoft_code)
.then(function(token)
{
res.send(token);
})
The Method:
var connection = nodeAxosoft(client_url, credentials);
return new Promise(function(resolve, reject){
console.log("CODE: ", axosoft_code)
var token = connection.Api.exchangeCodeForToken(axosoft_code, function(token){
console.log(token);
resolve(token)
})
The problem is that returns null
I had a look at the API lib api.js and found that:
https://github.com/Axosoft/node-axosoft/blob/master/lib/api.js
function exchangeCodeForToken(code, callback) {
_credentials.code = code;
_access_token = '';
_authenticateCredentails(function (err) {
if (!err) {
callback(null, _access_token);
} else {
callback(err);
}
})
}
So I have two questions:
Does anyone has an Idea what am I doing wrong?
What would be necessary to code the callback function?
The method expects a callback function but I don't really know how to do it.
EDIT:
return new Promise(function(resolve, reject){
var token = connection.Api.exchangeCodeForToken(axosoft_code, function(response,err){
if(!err){
console.log("token",response)
resolve(token);
}
else{
console.log("error",err)
resolve(token);
}
});
})
OR
var token = connection.Api.exchangeCodeForToken(axosoft_code, function(response,err){
if(!err){
console.log("token",response.body)
return response.body;
}
else{
console.log("error",err)
return err;
}
});
I am giving to my callback function two args (response and err), my problem is that I am falling at the else condition.
The output of err is something similar to a token though the documentation here shows that it should be like that:
{
"error" : "invalid_request",
"error_description" : "One or more parameters are missing: client_secret"
}
Another point is that the page is frozen waiting for something to happen but nothing happens.
Given that this is the input:
function exchangeCodeForToken(code, callback) {
_credentials.code = code;
_access_token = '';
_authenticateCredentails(function (err) {
if (!err) {
callback(null, _access_token);
} else {
callback(err);
}
})
}
You should format your call as:
exchangeCodeForToken(axosoft_code, function(err, response) {
if (err) {
// Deal with error
} else {
// Deal with response
}
}
Node functions often pass through error variables first so that you have to receive them, which is considered good practice.
I'm trying to put together a quick node.js/edge.js/C# bridge for a demo.
I have to use the ".Net calling Node.js" style, as the existing C# code uses a number of config values, which I can't add to node.exe.config as I will need to run several versions concurrently.
So I have this code:
private static async Task Start() {
Func<object, Task<object>> edge = EdgeJs.Edge.Func(#"
var login = require('login.js');
var edge = require('edge')
login({ email: 'user#example.com', password: 'shh' }, function callback(err, api) {
if (err) return console.error(err);
// This will keep listening until terminated
api.listen(function callback(err, message) {
if (err) return console.error(err);
// At this point I need to send the message back to this class so it can be processed..
console.log(message); // send the message to C#
// ... and then return the response via the api
api.send('response goes here');
});
});
return function (data, callback) {
callback(null, er...);
}
");
}
So, the code is waiting for messages in an event loop and responding. This all works with hardcoded values. But I need to submit the message back to the C# for processing, and I cannot work out how to communicate back and forth between edge.js and the C# app.
It must surely be via the callback, but I can't seem to start figure out how to structure it, and time is getting short. And I'm by no means a JavaScript expert.
How can I communicate between the edge code and the C# code from within the event loop using the callback?
You're right, it's via the callback. Since you're using async code, you have to wrap all your code inside the returned (edge) function, like this:
private static async Task Start() {
Func<object, Task<object>> edge = EdgeJs.Edge.Func(#"
// edge_callback is used to return values to the C# code
return function(data, edge_callback) {
var login = require('login.js');
var edge = require('edge')
login({
email: 'user#example.com',
password: 'shh'
}, function callback(err, api) {
if (err) return console.error(err);
// possible enhancement here by letting C# know there is an error
// edge_callback(err);
// This will keep listening until terminated
api.listen(function callback(err, message) {
if (err) return console.error(err);
// same thing here: edge_callback(err);
// At this point I need to send the message back to this class so it can be processed..
console.log(message); // send the message to C#
// use the callback, first param is error if there is any, second is the data
edge_callback(null, message);
// ... and then return the response via the api
api.send('response goes here');
});
});
}
");
}
I have ended up with something like this: there's a function defined on the data passed to edge, which edge then calls when a new message is received. That function then waits for the response, and passes it back to edge, which receives the result in (of course) another callback.
private static async Task Start() {
dynamic payload = new ExpandoObject();
payload.msgHook = NewMessage;
payload.login = new {
email,
password
};
var receive = Edge.Func(#"
return function(payload, edge_callback) {
var login = require('index.js');
login({
email: payload.login.email,
password: payload.login.password
}, function callback(err, api) {
if (err) {
edge_callback(err);
}
api.listen(function callback(err, message) {
if (err) { edge_callback(err); }
payload.msgHook(message,
function callback(err, result) {
if (err) {
edge_callback(err);
}
var msg = {
body: result.body,
url: result.url
}
api.sendMessage(msg, result.threadId);
});
});
});
}
");
var _ = await receive(payload) as IDictionary<string, object>;
}
private static Func<object, Task<object>> NewMessage {
get {
Func<object, Task<object>> hook = async m => {
string body, threadId;
if (!ProcessMessage(m as IDictionary<string, object>, out body, out threadId)) {
log.Error("Failed to process message: " + m.ToString());
}
api.SendMessage(body, threadId, phone);
var reply = await waitForReply(threadId);
var result = new {
body = reply
};
// Return the _result_ of the task.
return Task.FromResult<object>(result).Result;
};
return hook;
}
}
I am trying to run a put function to update a user in my mongoDB, but I am getting a 500 Internal Service error. I am using the angular-fullstack generator
I use this resource in my controller:
update(User) {
User.$update();
}
Here are the functions I call in the backend to try and put the data everything seems to be working fine except for when I call saveUpdates, it seems like that is triggering the 500 error.:
function handleError(res, statusCode) {
statusCode = statusCode || 500;
return function(err) {
res.status(statusCode).send(err);
};
}
// this seems to be the function giving me the problem.
function saveUpdates(updates) {
return function(entity) {
var updated = _.merge(entity, updates);
return updated.saveAsync()
.spread(updated => {
return updated;
});
};
}
function respondWithResult(res, statusCode) {
statusCode = statusCode || 200;
return function(entity) {
if (entity) {
res.status(statusCode).json(entity);
}
};
}
function handleEntityNotFound(res) {
return function(entity) {
if (!entity) {
res.status(404).end();
return null;
}
return entity;
};
}
export function updateUser(req, res) {
if (req.body._id) {
delete req.body._id;
}
User.findByIdAndUpdate(req.params.id)
.then(handleEntityNotFound(res))
.then(saveUpdates(req.body))
.then(respondWithResult(res))
.catch(handleError(res));
}
I have tried following recommendations on this page for angular-full stack, such as changing ._merge to ._extend to no avail.
I answered my question:
Angular-full stack utilizes lodash, so if you want to make put requests using ._merge like this:
function saveUpdates(updates) {
return function(entity) {
var updated = _.merge(entity, updates);
return updated.saveAsync()
.spread(updated => {
return updated;
});
};
}
then you need to import lodash into the user.contoller set up by the angular-fullstack yeoman generator.
import _ from 'lodash';
Im trying to create a function so i dont use the same code again and again but i keep getting internal error.I get the data and then i get the internal error so if i change something i need to refresh the page to be updated.I cant understand why i get the error.Here is the error
GET http://localhost:3000/api/pages 500 (Internal Server Error)
Object {data: "", status: 500, config: Object, statusText: "Internal Server Error"}
code:
function Get(some,that,res){
return some.find(function(err,that) {
if (!err) {
return res.send(that);
} else {
return res.send(500, err);
}
});
};
router.get('/pages', sessionCheck, function() {
Get(Page,pages,res);
});
UPDATE: i might doing something wrong so lets take it from the start.How can i create a function that do that so i dont reuse the same code again and again.
router.get('/pages', function(request, response) {
return Page.find(function(err, pages) {
if (!err) {
return response.send(pages);
} else {
return response.send(500, err);
}
});
});
and here is my full code
var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');
var Page= require('../models/page.js');
var bcrypt = require('bcrypt-nodejs');
function Get(some,that,response){
return some.find(function(that,err) {
if (!err) {
return response.send(that);
} else {
return response.send(500, err);
}
});
};
router.get('/pages', sessionCheck, function(request,response) {
Get(Page,pages,response);
});
router.METHOD will first call your function sessionCheck. You will then need to call next() within sessionCheck to call the next function, in which you are not defining any parameters (typically you would define req, res).
If you are using express your function call should probably be:
function someGetFunc(req, res, next)
You have res as the third parameter, so that might be the problem.
Now the Get function you have above is internal to an anonymous function that doesn't take in params, so what you are passing into it are either undefined or reference global scope variables.
ok i fixed it like that i shouldnt have left the function empty it required res,req
function Get(Some,that,res){
return Some.find(function(err,that) {
if (!err) {
return res.send(that);
} else {
return res.send(500, err);
}
});
};
router.get('/pages', sessionCheck,function(req,res) {
Get(Page,pages,res);
});