Maciej Stasiełuk, Vazco
Meteor Impact Hackathon 2022
Tips & tricks to get more out of your Meteor Methods
I assume that you know the basics.
If not, please check out Meteor University, which gives an excellent introduction to the concept:
…but let's make a quick recap :)
Meteor implementation of RPC:
Remote Procedure Calls
The idea itself goes back to the 1980s!
It is a form of client-server interaction where the client can invoke some code directly on the server.
REST
+ Optimistic UI
+ Guaranteed execution order
- No HTTP cache & other stateless benefits
- Less popular: less tooling, interoperability, etc.
Official package:
mdg:validated-method
Around 120 lines of code
(most of it related to mixins support)
Mongo is also susceptible to query injections.
You should not only check argument type (e.g., a string) but also content before using it in a query.
Meteor.methods({
removePost({ id }) {
Posts.remove({ _id: id });
}
});
Meteor.call('removePost', { id: { $ne: 'p0wn' });
Posts.remove({ _id: { $ne: 'p0wn'} });
Your server can be overloaded by Method requests.
To prevent this, you can implement Throttling with the DDPRateLimiter package.
Not everything must be reactive!
You can improve the scaling capabilities of your apps by fetching some data with Methods (similar to how you would do with REST).
With a neat trick, you can still retain MiniMongo features.
The Methods can be a big part of the perceived performance of your app.
Monitoring and understanding bottlenecks are crucial to improve scaling and performance.
Tools like APM in Galaxy Professional plans or MontiAPM can help you with that.
Do your methods contain secret code or execute proprietary algorithms you don't want to share publicly?
Do your Methods always start with isClient/isSimulation check?
Maybe putting them in the server only part of your app would be better.
Optimistic UI is not mandatory!
There are cases where chaining Methods one from another can be helpful.
The idea is simple - call a Method from a body of another one.
The authorization/connection will be shared between chained methods.
The simulation will execute correctly (if both methods are available for the client).
With the Validated Method pattern, all variables are passed as named arguments (in the first argument of a function).
This pattern is worth using even if not going for the Validated Methods.
It enables us to easily add and deprecate arguments, improving application maintenance over time.
Do you often find repeating code each time you call a Method?
Do you need cross app features, like a notification/toast when Method succeeds/fails?
Do you call Methods based on a result of another Method?
If so, think about introducing an action pattern to encapsulate those features in a single place.
Methods due to backward compatibility use the callback pattern, but it is very easy to promisify it for your convince.
const callMethod = (name, args) => new Promise((resolve, reject) => {
Meteor.call(name, args, (err, res) => {
err ? reject(err) : resolve(res);
});
});
callMethod('myMethod', { id: 1 })
.then(res => console.log(res))
.catch(err => console.error(err));
There are three ways to handle errors in your Methods:
By default, Methods are executed in the order they arrive (for a given connection) and wait for the previous one to end.
This is a good behavior but can lead to bottlenecks when we have a long-running Method, e.g., generating a report.
In such a case, we can use this.unblock() to bail out of the queue and don't block other requests.
A less-known fact: Meteor auto-retries your Method calls in case of network issues.
This is a rare case, but your Methods must be resistant to it by making them idempotent.
Most Methods are by default because the ID generation algorithm prevents inserting or removing a document twice.
But on some occasions (e.g., counters with $inc), this should be handled on the app level.
You can catch me at maciej.stasieluk@vazco.eu