Meteor - transfer data from API to Server to Client - javascript

I am struggling a bit with Meteor, i have this app that i would like to connect with an API client, which provides me a Secret API key, which i must not publish (in the client).
The thing is when i send the request, i get a JSON data, and i would like to pass this data to the client.
API > Server Call -> Client (Rendering).
But so far i have not come to a solution how can i do this.
I have a basic understanding how Meteor Works, but i have a good knowledge about JavaScript/NodeJS etc.
A little bit of help would really be appreciated.
Thank you.

This sounds like a good use case for a client making a call to a server-side method. The server can then use the secret key to make an HTTP request and send the result back to the client without exposing the key. Please note that your server-method must exist inside of a server directory to avoid inadvertently shipping the key to the client (see Structuring your application).
client
Meteor.call('getApiResult', function(err, result) {
if (result) {
return console.log(result);
}
});
server
Meteor.methods({
getApiResult: function() {
var secret = 'abc123';
try {
var result = HTTP.get('http://example.com/', {params: {key: secret}});
return result.data;
} catch (_error) {
return false;
}
}
});

Related

send http request to angular js

I know how to send an http request to a server using angular js. With the promise returned, I know how to listen for a response and manipulate the ui thereafter. But this approach cannot be used for what I have in mind.
However, what I cannot figure out, is how to send a request to a website.
I have a server localhost:800/receiveData which receives a POST request and then manipulate the UI and DoM on the angularjs site
app.get('/', function(req,res){
res.sendFile(__dirname+'/index.html')
})
app.post('/receiveData', function(req,res){
var data = req.body.data
// assume data is a boolean
if(data){
//show a view in index.html using angular js or anything else
}else {
//show a different view in index.html
}
});
Any help will be greatly appreciated. I have a need for angular js. Having a SPA is imperative. I am completely open to adding additional stacks if neccessary.
EDIT:
As pointed out by MarcoS, manipulation of dom should ideally not happen from the server side. I am combining IPFS with node js and angular js to develop a single page application. The swarm of nodes set up using IPFS has an open line of communication with my server (by design). Based on packets of data sent via the comm line to my server, I need to convey messages to the user via the index.html.
I think your approach is wrong: on server-side, you should NOT manipulate the UI and DOM...
You should just do server activity (update a database, send an email, ..., return a static page).
Then you can output a result (JSON/XML/... format) for your client-side calling script to read.
Following OP edit, what I do understand is he wants server push to the client.
To get serve side pushes, you should poll on the client.
In a controller:
function getServerState(changeState) {
return $http.get("/receiveData").then(function(res) {
changeState(res.data); // notify the watcher
}).catch(function(e) {
/* handle errors here */
}).then(function() {
return getServerState(changeState); // poll again when done call
});
}
Consuming it this way:
getServerState(function(status) {
$scope.foo = status; // changes to `foo` $scope variable will reflect instantly on the client
});
And, server side:
app.post('/receiveData', function(req, res) {
var data = req.body.data; // assume data is a boolean
res.end(JSON.stringify(data);
});

Hide an API key (in an environment variable perhaps?) when using Angular

I'm running a small Angular application with a Node/Express backend.
In one of my Angular factories (i.e. on the client side) I make a $http request to Github to return user info. However, a Github-generated key (which is meant to be kept secret) is required to do this.
I know I can't use process.env.XYZ on the client side. I'm wondering how I could keep this api key a secret? Do I have to make the request on the back end instead? If so, how do I transfer the returned Github data to the front end?
Sorry if this seems simplistic but I am a relative novice, so any clear responses with code examples would be much appreciated. Thank you
Unfortunately you have to proxy the request on your backend to keep the key secret. (I am assuming that you need some user data that is unavailable via an unauthenticated request like https://api.github.com/users/rsp?callback=foo because otherwise you wouldn't need to use API keys in the first place - but you didn't say specifically what you need to do so it is just my guess).
What you can do is something like this: In your backend you can add a new route for your frontend just for getting the info. It can do whatever you need - using or not any secret API keys, verify the request, process the response before returning to your client etc.
Example:
var app = require('express')();
app.get('/github-user/:user', function (req, res) {
getUser(req.params.user, function (err, data) {
if (err) res.json({error: "Some error"});
else res.json(data);
});
});
function getUser(user, callback) {
// a stub function that should do something more
if (!user) callback("Error");
else callback(null, {user:user, name:"The user "+user});
}
app.listen(3000, function () {
console.log('Listening on port 3000');
});
In this example you can get the user info at:
http://localhost:3000/github-user/abc
The function getUser should make an actual request to GitHub and before you call it you can change if that is really your frontend that is making the request e.g. by cheching the "Referer" header or other things, validate the input etc.
Now, if you only need a public info then you may be able to use a public JSON-P API like this - an example using jQuery to make things simple:
var user = prompt("User name:");
var req = $.getJSON('https://api.github.com/users/'+user);
req.then(function (data) {
console.log(data);
});
See DEMO

node.js and hapi: fetching data from a database synchronously

Coming from a .net world where synchronicity is a given I can query my data from a back end source such as a database, lucene, or even another API, I'm having a trouble finding a good sample of this for node.js where async is the norm.
The issue I'm having is that a client is making an API call to my hapi server, and from there I need to take in the parameters and form an Elasticsearch query to call, using the request library, and then wait for the instance to return before populating my view and sending it back to the client, problem being is that the request library uses a callback once the data is returned, and the empty view has long been returned to the client by then.
Attempting to place the return within the call back doesn't work since the EOF for the javascript was already hit and null returned in it's place, what is the best way to retrieve data within a service call?
EX:
var request = require('request');
var options = {
url: 'localhost:9200',
path: {params},
body: {
{params}
}
}
request.get(options, function(error, response){
// do data manipulation and set view data
}
// generate the view and return the view to be sent back to client
Wrap request call in your hapi handler by nesting callbacks so that the async tasks execute in the correct logic order. Pseudo hapi handler code is as following
function (request, reply) {
Elasticsearch.query((err, results) => {
if (err) {
return reply('Error occurred getting info from Elasticsearch')
}
//data is available for view
});
}
As I said earlier in your last question, use hapi's pre handlers to help you do async tasks before replying to your client. See docs here for more info. Also use wreck instead of request it is more robust and simpler to use

Accessing JSON from Node/Express Route?

I was wondering, since Node is written in JavaScript, and I'm using ES6 to write a little fun app, is there a way to access the object I send to the route without using ajax to get it from the server/api? In other words, can I say something like
import { jsonData } from '../api/server.js';
and then be able to use jsonData as a variable in my client side controller?
In other words... I would have something like this:
var DataController = (req, res) => {
let data_client = new DataClient();
data_client.getData().then(
(data) => {
res.render('index', { jsonData: jsonData });
},
(error) => {
res.send('An error occurred. Please check your connection settings.');
}
);
Is what I'm asking possible?
If not, would I just use an XHR request or fetch?
Just wondering what my options are since I want to use Node (4.x) to its full potential. Sorry if this question was confusing or vague.
I don't think that server side file will be accessible over client side.
If you make your server side file available on client and your server.js file is generic enough to run on client side as well along with correct client side export statement , then yes you can import the jsondata with syntax like
import { jsonData } from '../api/server.js';
and use it else where
Beware that there are limited browsers that support import statement
You can check the list from here

Which IP does a method use (user or server) on an API request?

I want to use an API in my meteor app. The API is restricted to a few requests per second per unique IP.
Does anyone know if the server IP or the user IP is used, when I make an API call in Meteor.methods like this
Meteor.methods({
searchTerm: function (term, lang) {
var parameters = {
"api_key": Meteor.settings.API
};
try {
var result = HTTP.call("GET", apiLink, { params: parameters });
return result.data;
} catch (e) {
return e;
}
}
}
Thanks in advance.
As already noted in the comments, if this code (the methods call itself) is runs on the server, then the method call (later with Meteor.call) is like a remote procedure call and the HTTP will be executed on the server only. If, however, this code, the methods call, is invoked on both the client and the server, then that defines a stub (http://docs.meteor.com/#/full/methods_header). That stub is executed in parallel on the client and the server. It is meant to help with latency compensation. I don't think you want that in this case though, since you are more concerned with the number of API requests. So I would suggest to leave it where it is right now (in the server folder somewhere). That way you can be sure that it will only execute on the server and not the client, and hence use the server IP.

Categories