2

Hello is there any way to use JS environment built in ArangoDB to execute custom JS? I'd like to set up path to my JS files which would be executed instead of foxx application files.

2 Answers 2

2

Via GitHub: https://github.com/arangodb/arangodb/issues/1723#issuecomment-183289699

You are correct that modules are cached independently of the routing cache. Clearing the module cache (or preventing a module from being cached) is currently not supported.

The actions mechanism is really only intended as an internal API and only supported for backwards compatibility with early ArangoDB versions and some edge cases.

As you may have noticed while digging through the ArangoDB source code, Foxx provides a per-service module cache which is cleared whenever a Foxx service is reloaded. I would strongly encourage you to see whether Foxx fits your use case before continuing to dig into the actions mechanism.

It's actually possible to create a Foxx service with just two files (a manifest and a controller file) and without using repositories or models (you can just use the same APIs available in actions).

You just need a controller file like this (e.g. ctrl.js):

'use strict';
const Foxx = require('org/arangodb/foxx');
const ctrl = new Foxx.Controller(applicationContext);
ctrl.get('/', function (req, res) {
  res.send('Hello World');
});

with a manifest.json like this:

{
  "name": "my-foxx",
  "version": "0.0.0",
  "controllers": "ctrl.js",
  "defaultDocument": "",
  "engines": {"arangodb": "^2.8.0"}
}

You can then mount the service (upload a zip bundle) at a path like /db and access it:

curl http://localhost:8529/_db/_system/db

The upcoming 3.0 release will remove a lot of the existing conceptual overhead of Foxx which will hopefully make it even easier to get started with it.

Sign up to request clarification or add additional context in comments.

Comments

1

Yes, this can be done with User Actions. Foxx was created as a more comfortable alternative and is likely a better choice for non-trivial applications. The documentation can be intimidating but Foxx services can actually be very lightweight and simple (see my other answer). If you really don't want to use Foxx for this, here's how to do it manually:

First create a virtual module in the _modules system collection:

var db = require('org/arangodb').db;
db._modules.save({
  path: '/db:/ownTest',
  content: `
    exports.do = function (req, res, options, next) {
      res.body = 'test';
      res.responseCode = 200;
      res.contentType = 'text/plain';
    };
  `
});

Then create a route that uses it:

db._routing.save({
  url: '/ourtest', 
  action: {
    controller: 'db://ownTest'
  }
});

Finally, tell ArangoDB to update its routing cache so it notices the new route:

require('internal').reloadRouting();

If you install your JavaScript module to the js/common/ or the js/server/ directory you can use the module name (e.g. myOnDiskModule) instead of the virtual module name "db://owntest" in the controller.

For smaller modules you can just define the function inline using callback instead of controller:

db._routing.save({ 
  url: '/hello/echo',
  action: { 
    callback: `
      function (req, res) {
        res.statusCode = 200;
        res.body = require('js-yaml').safeDump({
          Hello: 'World',
          are: 'you here?'
        });
      }
    `
  } 
});

Remember to always update the routing cache after changes to the routing collection:

require('internal').reloadRouting();

Note: the callback implementation in 2.8 has a bug that will be fixed in 2.8.3. If you want to apply the fix manually, it's in commit b714dc5.

8 Comments

I was able to run custom script from disk which logged a string to console, but when I changed the script it didn't do anything. It didn't do new stuff but also wasn't logging anymore. Is there some cache or something that needs to be refreshed? I tried to run require('internal').reloadRouting(); in JS Shell, but it didn't help. After database process restart, new code gets applied. Is there any way to avoid restarting database?
Here for FOXX offers development mode. You have to do this yourselves by using require("internal").load("/some/test/.js")
dothebart, the command results in TypeError: require(...).load is not a function
How would I access database other than _system from such module?
you can place _db/[databasename]/... in the URL or run require("internal")._useDatabase() before the require. However, the recommended way of doing this is to use FOXX.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.