List Meteor methods registered with Meteor.methods()? - meteor

Wondering if there was a way to get a list of the current Meteor.methods that have been registered.
for example if a post method is registered like so:
Meteor.methods({
post: function() {
//code
}
});
Is there a way to access a list of these methods? Ideally it would be via a method but if it was stored in an accessible variable like Meteor.__methods that would work as well.
I've combed through the documentation and the Meteor global in the browser but did no find anything useful. Any Ideas?

After Digging more on the Server side of meteor, it appears that the methods are stored in an array Meteor.default_server.method_handlers which is accessible on the server but not on the client.
Only way to expose it client side seems to be registering a method server side and then returning a list of the keys.

On the client you can do:
Meteor.connection._methodHandlers
It gives you a dictionary of function names to functions.

Related

In Meteor.js, what's the difference between method-based database API design and the subclass approach?

Namely, what are the advantages and disadvantages of the following approaches to building a server-side database API in Meteor?
Method-based
import Db from 'Db';
Meteor.method({"insert": (data) => {Db.insert(data)});
Subclass-based
import {Mongo} from "meteor/mongo";
class MyCollcetion extends Mongo.Collection {
insert: (data) => {super.insert(data);}
}
This problem has been solved below; there is a similar question for further reading: Meteor method vs. deny/allow rules
This is mainly a matter of ease vs control. Subclassing may be easier for simple things, and methods are more powerful.
This can also be affected by your state of mind (or affect it): CRUD vs. action-based mutation.
insert/update/remove go well with a CRUD state-of-mind, while you can associate methods with action-centric RPC mutators.
Eventually, this is a matter of personal preference, so I will try to give a short factual description and let the readers to decide based on their taste.
Subclassing
By default, Meteor automatically generates mutation methods (insert, update, remove) when a collection is instantiated.
Those methods are called behind the scenes when calling MyCollection.insert(mutator, cb) on the client side (outside client-side method code). When arriving to the server, the data are first passed through allow/deny rules and then executed.
When subclassing, you override those methods and get a 'hook' into the process.
Using methods
When defining a Meteor method you get full control of the process.
You set the parameters and the name of the method and you can perform the validation and authorization as you wish.
You can also create a method stub for client-side use, which generates optimistic UI until the results of the method server execution are received.
You can use something like a validatedMethod to get some extra validation logic and modularity to your method.
You can also prevent the creation of the default mutation methods by setting a false value for the defineMutationMethods option when instantiating the collection. You can also forbid direct mutation from the client by supplying the appropriate deny rules.
While subclassing allows you to use MyCollection.insert(...), etc. on the client, you need to call the method name with the arguments that you defined in order to mutate data.

Different parameters in Meteor call stubs

I have a meteor method that's supposed to handle file/image uploads by passing a cdn key, which is just a string.
For latency compensation though, I want to add the actual image blob to LocalMongo, that way I can add an image preview.
This is a problem since I want to just pass a string key to my server method, while I want to pass a file blob to my client method stub. Does Meteor support this? I don't want to pass the image blob to my server (as doing so would serialize the blob/make the call costly).
A solution I'm thinking of is to just define two Meteor methods with different names, the first one being for the client and the other for the server, and just calling them both with the proper parameters. Is this the proper way to do this in Meteor?
EDIT: My solution above doesn't actually work because Meteor realizes there is no method on the server (and nukes the local changes of my client method)
Just a suggestion, you can save the file blob in a Session variable and access in the method when the method stub is called from client, like this,
Meteor.methods({
'yourMethod': function (key) {
if (Meteor.isClient) {
var fileBlob = Session.get('my-file-blob'); //set this variable just before calling this method. And don't forget to remove it when template is destroyed.
} else {
}
}
});
Like I said, I didn't test it but just a suggestion. Hope it helps.

Sails.js: How to properly handle request parameters/queries to backend?

I'm developing an application using Sails.js in the backend, and I'm having trouble validating requests as follows:
I want to block access to certain resources based on an attribute of the logged in user. I have the REST API blueprints enabled, and the shortcut routes disabled. I have the following piece of code:
User.findOne()
.where(query)
.exec(function(err, user) {
if (user.team !== req.user.team) {
return res.view('403');
}
return next();
});
where query is the criteria by which I'd like to do the database search. The idea is that the user can only access the requested user if they're in the same "team".
The problem is that the user can make at least the following kinds of requests to the backend, maybe more (I'm not too experienced with sails, please enlighten me if there's even more types):
localhost:1337/user?id=1
In this case, the req object will have a req.query attribute, which I can pass on as query as it is. Now, the following kind of request is also possible:
localhost:1337/user/1
Here req.query will be an empty object, while req.params is [ id: '1'].
Now this is troublesome; if I understand correctly, the the type of req.params isn't a JSON object, so I can't pass it as query as it is. In addition, I'd have to convert the id parameter into Int since it's originally a string for some reason (?).
What I'm asking is if there's a way I may have missed that handles both kinds of requests in the same way, or whether I'll have to take both cases into account in a way like
var query = isEmpty(req.query) ? req.params : req.query
in which case I'd have to convert req.params into something I could pass to the database search and would generally be troublesome and inconvenient. I'd like to know what the best way to handle this situation is.
Well, it's funny how right after posting a question you happen to find an answer. Apparently there's a function called req.allParams() which "Includes parameters parsed from the url path, the query string, and the request body." according to the official docs. I've no idea how I never bumped into this before, but now I did and it seems to work, so hooray!

Meteor collection returns no results except in template

I'm new to the Meteor framework, and am having problems accessing data from my collection, outside of a template.
I have a small mongo collection and can retrieve and present its data without problems by using a template. However, when I try to get a cursor or array to use more directly, I get no results returned.
In my script, using find
var dataFind = Fakedata.find();
console.log(dataFind);
console.log(dataFind.count());
gives a cursor object, but a count of zero.
var dataFetch = Fakedata.find().fetch();
console.log(dataFetch);
console.log(dataFetch.length);
gives an empty array, length of zero.
Using the same find() or fetch() from the JS console gives populated objects as I would expect the code above to do. Within a meteor template, everything seems to work fine as well, so the pub/sub seems to be correct.
Any clues as to what I'm doing wrong here?
It looks like your subscriptions aren't ready at the time you try to access your collection data, this is a common gotcha.
When you access your collection data via templates, it is most likely via the use of template helpers which happen to be reactive, so they will rerun when your collections are ready thus displaying the correct data.
When accessing your collections in a non-reactive script though, they will appear empty if the subscription is not yet ready.
You can try using this pattern in your script to execute code only when the subscription is ready :
Meteor.subscribe("mySubscription",function(){
// we are inside the ready callback here so collection date is available
console.log(Fakedata.find().fetch());
});
If you are looking for a more robust approach, try looking at iron:router waitOn mechanism.

Why have a separate call to get Json?

I need to get some Json to the client side from the server and it's somewhat troublesome as almost all tutorials assume an Ajax call to a separate action to get the Json.
This led me to think that there must be some reason why it is done this way. In Asp.Net MVC we can pass a Model along with the view to get the information but we can't seem to easily pass a Json object. Instead you are supposed to make a separate call to get this information.
What if the Json info is known when the page is generated, why not generate it at the same time?
I'm sorry if I wasn't clear enough. While it's nice to hear of ways to get Json to the client, the question is actually whether there is a specific reason the Ajax call method is much more popular, like security or anything like that.
Can you put something like this into your view? (rough pseudo code, assuming using a Razor view)
< script >
var myJSON = { Field: #model.Field, Field2: #model.Field2 };
< /script >
Because you do not need both at the same time... on the first call will be to get html (the view of the data - represented by a view model), and any ajax calls will be to get the possibly updated data (json serialized view model).
No reason why you can't. You could use the javacript serializer to create a JSON string that drop on the page. You could also create an action that return the json string that you called from a script tag.
What you want if you're using KnockOut, would be the Mapping plugin that turns an ordinary JS object, like that generated above, into an observable ready for KnockOut to use. See here from info. http://knockoutjs.com/documentation/plugins-mapping.html
You can use content-negotiation by setting accept header. This is considered a best practice (and according to some RESTful).
This needs to be supported and implemented at server as well. ASP NET MVC does not make it easy to support content-negotiation and you have to implement it yourself by if-else or using ActionFilter and implementing action selector.

Resources