Meteor client side methods - meteor

I have a Meteor.method defined on the server side (in .js in /server) and I can call it just fine (with callback) from a client-side template script.
I want to do a similar thing but would like it all to be client side so I moved the method to a client script but the result comes back as 'undefined'.
Template.showDialog.events({
'click #clickme' : function() {
Meteor.call('foo', 'ola', function(error, result) {
alert('here');
alert(result);
});
}
});
Meteor.methods({
foo: function (myarg) {
return myarg+'CLI';
}
});

See the Meteor docs, where it is explained that methods on the client are stubs, not actual methods:
If you do define a stub, when a client invokes a server method it will also run its stub in parallel. On the client, the return value of a stub is ignored. Stubs are run for their side-effects: they are intended to simulate the result of what the server's method will do, but without waiting for the round trip delay. If a stub throws an exception it will be logged to the console.
Since the result is ignored, you're seeing undefined. Don't use methods on the client for this purpose. Just use a javascript function.

From the docs:
Calling methods on the client defines stub functions associated with server methods of the same name.
Basically, you need to define the method on the server side. It's also not clear why you'd want to define a method on the client and then call it on the client as well. Would a vanilla javascript function not do the job perfectly well?
Apologies if I've misunderstood what you're trying to achieve here.

Related

intercept firebase-functions response (middleware)

For my Google Assistant/Dialogflow project, I am trying to intercept every response my firebase-functions endpoint is sending back to Dialogflow. I can easily intercept the request, but the response gets built within several functions (one function for every Intent), and I don't want to include an interceptor in every function.
Is it possible to have a middleware or is there a callback provided when a response is send out, sort of a global interceptor for every response?
I have found the following in the Docs: https://firebase.google.com/docs/functions/http-events#use_middleware_modules_with
However, I am unsure where this goes. Note that I am not using a custom express setup, but I am using the native implementation on firebase directly.
serialize() method is called on conversation right before the response is sent back, so what you can do is to extend the conversation object(based on the library you are using) and overwrite the serialize method to do whatever you need to do. don't forget to call the original serialize method and return the value in your new method.
Since you are using Dialog Flow with Firebase for your fulfilment, I am expecting you are also using actions-on-google package.
serialize() is a function which is called to generate the response. You can override this function and intercept the request and response. Try this code and thank me later. 😉
app.middleware((conv) => {
const serializeCopy = conv.serialize;
conv.serialize = () => {
const response = serializeCopy.call(conv);
console.log(conv.request, response);
return response;
};
});
Cloud Functions does not expose any sort of middleware or interceptors for HTTP requests or responses. You will have to build something yourself, probably with an Express app that you build yourself. You can host an Express app on Cloud Functions.
I wanted something similar to intercept all conversations back and forth for logging purposes. I ended up writing a function that I use to send a conversation. For eg:
const intercept = (conv, sentence) => {
//My Interceptor code
conv.ask(sentence)
}
Now anytime I want to send a response, I would use:
intercept(conv, "Speak this")

Router.current().route.getName() is returning an error server side

Router.current().route.getName() is returning an error when I use it in a method call (server side method). I thought they say Iron-Router is supposed to work both client and server side. The error I get is
Error invoking Method 'mySeverSideMethod': Internal server error [500]
Please help.
You are half way right, the router works on both client and server. However the server-side implementation is meant for server side routes (eg. REST endpoints). There is no "state" sharing between client/server with iron:router (when invoked inside methods), so Router.current().route.getName() is going to throw you this error, because Router.current() is undefined.
Yes, iron:router can create server side routes, but that api is client only
From the docs:
Router.route('/download/:file', function () {
// NodeJS request object
var request = this.request;
// NodeJS response object
var response = this.response;
this.response.end('file download content\n');
}, {where: 'server'});
You have access to the NodeJS request object so you should be able to find what you need there, e.g. this.request.route, this.request.path.
When calling a Method, you're not going through a 'route' as defined by Iron-Router: it's a route defined by the Meteor framework. It does not care what route the client is on.
So, if you need to know from what page the client is calling the endpoint, you should pass it as a parameter to the Method.
Meteor.methods({
"myEndPoint": function(route) {
// use route here.
return //something
}
})

Meteor - call method from client & server method

What will happen if from a method that is shared by the client and the server I call another method that is on the server only? Will it get called twice? Only once from the server? Only once from the client?
//lib/methods.js
Meteor.methods({
test: function() {
/*do some stuff that needs to update the UI quickly*/
Meteor.call('doSomeSecureStuff', Meteor.isClient);
}
});
//server/methods.js
import secureStuff from './secureStuff.js';
Meteor.methods({
doSomeSecureStuff: function(originIsClient) {
console.log(originIsClient);
secureStuff();
}
});
From my tests it only gets called once from the server, but since I've found no doc on that I wanted to make sure 1) this is what actually happen and 2) will stay like this in the future
(As suggested by the example, a use case for which I can't just wrap the server part in Meteor.isServer is when I need to load code that is only available on the server)
Yes, only once on the server.
You can wrap the server part of a shared method with this.isSimulation
When you run a shared method it first runs a simulation on the client and then on server - updating the client with its results (which are usually the same - which is why it's called Optimistic UI).

Does Meteor.call in server side without callback block server?

For example:
server/method.js
Meteor.methods({
insertPost: function(post) {
//call another method
var ret = Meteor.call('longTimeMethod', post.data); // A
// ...
}
})
Meteor doc says
If you do not pass a callback on the server, the method invocation will block until the method is complete.
since nodejs is single thread, if A costs 60 seconds, the whole server will not response to any requests during this 60s?
No, not the whole server will block, only the fiber running for this particular client. If you don't want that, then you can simply call this.unblock() before your method call, and a new fiber will be used for future method calls from that client, see http://docs.meteor.com/#/full/method_unblock.

How to call external rest service from angularjs?

I am trying to call an external REST service from angular using $http service.
The thing is that I am stuck on the $http.get method, because everytime I call the rest service i get an error with status = 0 and no information in the data parameter of the error callback.So far I've tried calling a local service runnig on port 5000 : $http.get('http://localhost:5000/ping') and this is supposed to return a json object with a property and a value. Another approach was calling http://api.flickr.com/services/rest/?method=flickr.test.echo&name=test in the hope of getting an answer. For both of them I get the same error: that I mentioned earlier.The call is made from an angular controller that has injected the http service.Thanks.
Have you tried:
$http({method: 'GET', url: 'someURL'}).
success(function(data, status, headers, config) {
//set view model or do something.
}).
error(function(data, status, headers, config) {
});
Make sure that you have passed the parameters correctly if there are any.
The general syntax should be like the following :
$http.get('../link/yourApplication/searchBySomeNumber?someNum='+$scope.someNum+'&asOfDate='+asOfDate+'&status=undefined')
.success(function(data, status, headers, config) {
//your code
console.log('Data return successful');
})
.error(function(data, status, headers, config) {
$scope.status = status;
alert('Info Error');
console.log('Group Info Error');
});
As $http returns a Promise, you can use the .then() method to log your results when the promise is resolved, or log an error in case anything goes wrong:
$http.get('http://localhost:5000/ping')
.then(function(returnedJson) {
console.log(returnedJson.data);
})
.catch(console.error) // or $log.error if you are using $log from Angular
Please note that the clean JSON response is obtained by logging the .data property of the returnedJson object. As it is a Promise, it contains other information that are not relevant to consume the web service.
Also note that the web service you want to consume should also be in the same domain as your Angular app, otherwise you may incur into a Cross Domain error, unless the service allows usage from external websites by exposing a Cross Domain Policy.
(Find more info here: Can someone post a well formed crossdomain.xml sample?)
If that's the case, this post should be helpful:
jQuery AJAX cross domain
Hope this helps.

Resources