I have several functions that I'd like to replicate across different use cases in various requests and folders within the same collection (I'm using it as a template mostly, so it'll be pulling in variables externally)
There are many different suggestions in the Postman documentation but what's the best way to re-use code for such a use case?
What I've been doing lately is adding functions to my collection level pre-request script like so
collectionUtils = {
clearEnvData: function (pm) {
some useful code
},
// called after every request to ensure server coverage durring smoke testing.
cycleCurrentServer: function (serverCount, pm) {
some useful code
}
}
Then wherever I want to use these methods I do something like this
collectionUtils.cycleCurrentServer(index, pm);
I think generally the best way is to externalize the code into a library. You'll then make changes to the library and those changes will be reflected everywhere. Now there are several ways to implement this method, I'll leave with with the two that make sense for your use case:
Load your library from a remote site
If you are using some sort of development workflow that publishes your changes upstream, and you have your library published somewhere, you can load it at runtime:
pm.sendRequest("https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.11.0/dayjs.min.js", (err, res) => {
//convert the response to text and save it as an environment variable
pm.collectionVariables.set("dayjs_library", res.text());
// eval will evaluate the JavaScript code and initialize the min.js
eval(pm.collectionVariables.get("dayjs_library"));
// you can call methods in the cdn file using this keyword
let today = new Date();
console.log("today=", today);
console.log(this.dayjs(today).format())
})
Store your code on a collection variable and load it that way
A less pretty way to do it but more convenient to a lot of folks is just to drop the whole library into a collection variable like this:
Then you can load it when you need it:
const dayjs_code = pm.collectionVariables.get('dayjs_code');
// Invoke an anonymous function to get access to the dayjs library methods
(new Function(dayjs_code))();
let today = new Date();
console.log(dayjs(today).format())
In both cases when you update your library you either have to republish it or copy paste again to the collection variable. However that surely beats copy pasting a piece of code to 20 odd places and figuring out what's updated, what's not and fighting bugs while at it.
Related
I'm using a query on both server and client (pub/sub). So I have something like this at a few different locations.
const FOO = 'bar';
Collection.find({property:FOO})
Foo may potentially change and rather than have to update my code at separate locations, I was thinking it may be worth it to abstract this away to a global variable that is visible by both client and server.
I created a new file 'lib/constants.js' and simply did FOO = 'bar; (note no keyword). This seems to work just fine. I found this solution as the accepted answer How can I access constants in the lib/constants.js file in Meteor?
My question is if this a desired pattern in Meteor and even general JS.
I understand I can abstract this away into a module, but that may be overkill in this case. I also think using session/reactive vars is unsafe as it can kinda lead to action at a distance. I'm not even gonna consider using settings.json as that should only be for environment variables.
Any insights?
yes, If you are using older version of meteor then you can use setting.json but for updated version we have import option.
I don't think the pattern is that bad. I would put that file in /imports though and explicitly import it.
Alternatively, you can write into Meteor.settings.public from the server, e.g., on start-up, and those values will be available on the client in the same location. You can do this without having a settings file, which is nice because it doesn't require you to make any changes between development and production.
Server:
Meteor.startup(() => {
// code to run on server at startup
Meteor.settings.public.FOO = 'bar';
});
Client:
> console.log(Meteor.settings.public.FOO);
bar
This is actually a b̶a̶d̶ unfavoured pattern because with global variables you cannot track what things changed and in general constructing a modular and replaceable components is much better. This pattern was only made possible due to Meteor early days where imports directory/pattern was not supported yet and you'd have your entire code split up between both,server and client.
https://docs.meteor.com/changelog.html#v13220160415
You can find many write ups about it online and event stackoverflow answers so I don't want to restate the obvious.
Using a settings.json variable is not an option since we may dynamically change so what are our options? For me I'd say:
Store it the database and either publish it or retrieve it using methods with proper access scoping of course. Also you can dynamically modify it using methods that author DB changes.
Or, you may try using Meteor.EnvironmentVariable. I'd be lying if I said I know how to use it properly but I've seen it being used in couple Meteor projects to tackle a similar situation.
https://www.eventedmind.com/items/meteor-dynamic-scoping-with-environment-variables
Why are global variables considered bad practice?
If I write a plugin which requires a very large initialization (14 mb JavaScript which takes 1 minute to set itself up), how can I make this object persistent (for lack of a better word) across the JavaScript files used in a Meteor projects?
After the initialization of the plugin, I have an object LargeObject and when I add a file simple_todo.js, I want to use LargeObject without it taking a minute to load after EVERY change.
I cannot find any solution.
I tried making a separate package to store this in Package object, but that is cleared after every change and reinitialized.
What would be the proper way of doing that? I imagine there should be something internal in Meteor which survives hot code push.
Here are two possible solutions I:
Cache some of its properties inside Session
Cache some of its properties inside a simple collection
Use a stub in your local environment.
Session can only be used client side. You can use a collection anywhere.
Session
client
example = function () {
if(!(this.aLotOfData = Session.get('aLotOfData'))) {
this.aLotOfData = computeALotOfData()
Session.set('aLotOfData', this.aLotOfData)
}
}
Here, no data has to be transferred between client and server. For every new client that connects, the code is rerun.
Collection
lib
MuchDataCollection = new Mongo.Collection('MuchDataCollection')
server
Meteor.publish('MuchData', function (query) {
return MuchDataCollection.find(query)
})
server
example = function () {
if(
!this.aLotOfData = MuchDataCollection.findOne({
name: 'aLotOfData'
}).data
) {
this.aLotOfData = computeALotOfData()
MuchDataCollection.insert({
name: 'aLotOfData',
data: this.aLotOfData
})
}
}
Even dough you can access the collection anywhere, you don't want anyone to be able to make changes to it. Because all clients share the same collection. Collections are cached client side. Read this for more info.
Stub
A stub is probably the easiest to implement. But it's the worst solution. You'll probably have to use a settings variable and still end up having the code for the stub inside the production environment.
What to choose
It depends on your exact use-case. If the contents of the object depend on the client or user, it's probably best to use a session-var. If it doesn't go for a collection. You'll probably need to build some cache-invalidation mechanisms, but I'd say, it's worth it.
I am writing a piece of javascript (ecmascript) within a 3rd-party application which uses embedded Rhino. The application may start multiple Java threads to handle data concurrently. It seems that every Java thread starts its own embedded Rhino context which in turn runs my script.
The purpose of my script is, to receive data from the application and use it to maintain the contents of a particular file. I need a fail-safe solution to handle the concurrency from my script.
So far, what I have come up with is to call out to java and use java.nio.channels.FileLock. However, the documentation here states:
File locks are held on behalf of the entire Java virtual machine. They are not suitable for controlling access to a file by multiple threads within the same virtual machine.
Sure enough, the blocking call FileChannel.lock() does not block but throws an exception, leading to the following ugly code:
var count = 0;
while ( count < 100 )
{
try
{
var rFile = new java.io.RandomAccessFile(this.mapFile, "rw");
var lock = rFile.getChannel().lock();
try
{
// Here I do whatever the script needs to do with the file
}
finally
{
lock.release();
}
rFile.close();
break;
} catch (ex) {
// This is reached whenever another instance has a lock
count++;
java.lang.Thread.sleep( 10 );
}
}
Q: How can I solve this in a safe and reliable manner?
I have seen posts regarding Rhino sync() being similar to Java synchronized but that does not seem to work between multiple instances of Rhino.
UPDATE
I have tried the suggestion of using Synchronizer with org.mozilla.javascript.tools.shell.Global as a template:
function synchronize( fn, obj )
{
return new Packages.org.mozilla.javascript.Synchronizer(fn).call(obj);
}
Next, I use this function as follows:
var mapFile = new java.io.File(mapFilePath);
// MapWriter is a js object
var writer = new MapWriter( mapFile, tempMap );
var on = Packages.java.lang.Class.forName("java.lang.Object");
// Call the writer's update function synchronized
synchronize( function() { writer.update() } , on );
However I see that two threads enter the update() function simultaneously. What is wrong with my code?
Depending how Rhino is embedded, there are two possibilities:
If the code is executed in the Rhino shell, use the sync(f,lock) function to turn a function into a function that synchronizes on the second argument, or on the this object of its invocation if the second argument is absent. (Earlier versions only had the one-argument method, so unless your third-party application uses a recent version, you may need to use that or roll your own; see below.)
If the application is not using the Rhino shell, but using a custom embedding that does not include concurrency tools, you'll need to roll your own version. The source code for sync is a good starting point (see the source code for Global and Synchronizer; you should be able to use Synchronizer pretty much out-of-the-box the same way Global uses it).
It is possible that the problem is that the object on which you are trying to synchronize is not shared across contexts, but is created multiple times by the embedding or something. If so, you may need to use some sort of hack, especially if you have no control over the embedding. If you have no control over the embedding, you could use some kind of VM-global object on which to synchronize, like Runtime.getRuntime() or something (I can't think of any that I immediately know are single objects, but I suspect several of those with singleton APIs like Runtime are.)
Another candidate for something on which to synchronize would be something like Packages.java.lang.Class.forName("java.lang.Object"), which should refer to the same object (the Object class) in all contexts unless the embedding's class loader setup is extremely unusual.
[I'm a total newbie to Javascript so take it slow.]
I'm working on an app in node.js which will have a list of plugins. Each "plugin" should be a function (or 2) that can take a string and do something with it. The app should call each plugin in turn and pass it the string. Depending on the result it might call another function in that plugin etc...
What's the best way to design this in Javascript? I don't mind having to modify the app to add every plugin as its developed but would rather avoid having to do this a lot.
Right now I'm just thinking created a module for every module then "require" it within the primary app and call the function but that seems cludgy for a few reasons (a) I need to change the parent app quiet a bit for every new plugin, (b) there's no interface I can enforce on the plugins. I was kind of hoping there was some sort of contract I could force the plugins to respect.
You can list the plugin directory, and require each file. If each file adds a function to an existing object (say, myapp.plugins), you can just forEach the object and invoke each function. You can't really enforce a contract in the code without doing weird things like invoking an AST parser; you're better off doing unit testing on plugins to make sure they work in isolation.
EDIT:
Can you elaborate a bit on this part: "If each file adds a function to an existing object (say, myapp.plugins), you can just forEach the object and invoke each function."?
var invokePlugins = function() {
var args = arguments.slice(0);
myapp.plugins.forEach(function(plugin) {
plugin.apply(plugin, args);
});
}
invokePlugins("this", "gets", "passed to", "each plugin");
Your architecture is unclear, so this is just a very rough idea of what you could do.
Are there any reliable techniques for storing prototype-based libraries/frameworks in mongoDB's system.js? I came across this issue when trying to use dateJS formats within a map-reduce. JIRA #SERVER-770 explains that objects' closures - including their prototypes - are lost when serialized to the system.js collection, and that this is the expected behavior. Unfortunately, this excludes a lot of great frameworks such as dojo, Google Closure, and jQuery.
Is there a way to somehow convert or contain libraries such that they don't rely on prototyping? There's some promise to initializing before the Map-Reduce and passing them in through the scope object, but I haven't had much luck so far. If my approach is flawed, what is a better way to enable server-side javascript re-use for mongo?
Every query using JS may reuse or get a brand new JS context, on which stored JS objects are loaded.
In order to do what you want, you need either:
mongod to run the stored code automatically when installing it
mapreduce to have an init method
The first is definitely the more interesting feature.
Turns out that mongodb v8 build automatically does it (but not officially supported), but not the official spidermonkey build.
Say you store code like:
db.system.js.save({ _id: "mylib", value: "myprint = function() { print('installed'); return 'installed';" }
Then in v8 you can use myprint() freely in your code, but with SM you would need to call mylib() explicitly.
As a workaround you can create another method:
db.system.js.save({ _id: "installLib", value: "if (!libLoaded) mylib(); libLoaded = true;" }
And call it from your map() function.
Created ticket in order to standardize engines and allow automatic run:
https://jira.mongodb.org/browse/SERVER-4450