Documentation

Create databases and use the powerful REST API.

Visit the blog for in-depth articles and tutorials.

Codehooks

Codehooks are JavaScript functions which can intercept REST API calls to your database. Codehooks gives you greater flexibility and power than using webhooks.

Some typical use-cases for codehooks are:

  • custom logic
  • validation and calculation
  • system integration

Codehooks can also run as background jobs to perform tasks at specific times or intervals (using crontab).

A codehook is a plain JavaScript function with a specific name to indicate when it's invoked, e.g.

function beforeGET(req, res) {
    ...
    res.end();
}

This function is called before a GET request.

Codehooks are created in the Collection settings, under the "Codehook" tab.

example codehooks

Codehook API

The codehooks listed here intercept API traffic and internal traffic to your database. They are invoked either before or after combined with one of the http verbs: GET, POST, PUT and DELETE. Only the combinations listed here are available.

CodehookAvailable parametersDescription
Restful hooks
beforeGET(req, res)req.query, req.hintCalled before a GET operation
beforePUT(req, res)req.bodybefore a PUT
afterPUT(req, res)req.bodyafter a PUT
beforePOST(req, res)req.body, res.end([optional data, error])before a POST
afterPOST(req, res)req.body, res.end()after a POST
beforeDELETE(req, res)req.body, res.end([optional error])before a DELETE
afterDELETE(req, res)req.body, res.end([optional error])after a DELETE
Background hooks
runJob(req, res)res.end("Optional message to log")triggers on a crontab expression

Database API functions

FunctionParametersDescription
db.get(path, query, hint, callback)path: REST url, query: query object, hint: hint object, callback: function(error, data)get operation to the current database. E.g. db.get('/rest/customer',{}, {}, function(error, data){...}
db.put(path, data, callback)path: REST url, data: JSON, callback: function(error, data)put operation to the current database
db.post(path, data, callback)path: REST url, data: JSON, callback: function(error, data)post operation to the current database
db.delete(path, data, callback)path: REST url, data: JSON, callback: function(error, data)delete operation to the current database

Network API functions

FunctionParametersDescription
request(options, callback)options: json, callback(error, response, body)Network API
slack(options, callback)options: Slack options as json, callback: function(result)Send a message to Slack

Utility API functions

FunctionParametersDescription
log.debug(str, ...)Variable list of arguments log.info, log. debug, log. error, log.fatalWrites output to Rest inspector
async.series(funcarray, callback)Array of functionsCall an array of functions in a sequence and callback when all are done
async.apply(function, arguments)Apply one function with argumentsCreates a continuation function with some arguments already applied. Add to array and use with async.series
template(str, context)Run Handlebars on str with context json dataHandlebars templating function

Return values from a codehook

A codehook must call req.end() when it's work is done. Failing to to so will lead to a timeout, and finally degrading the performance of your system.

Return methodParametersDescription
res.end()-na-Normal return, no data
res.end({"data": {}})jsonChange data on POST or PUT
res.end({"error": [{field:<fieldname>,message:<message>},...]})jsonValidation on POST or PUT
(field name is optional).
res.end({"query": {}, "hint": {}})jsonChange query or hint on GET

Examples

beforeGET

var beforeGET = function(req, res) {
    log.debug("Calling get ", req.query, req.hint);
    // modify all queries to only show people with Hunter as lastname
    req.query.lastname = "Hunter";
    res.send({"query": req.query});
}

beforePUT

// helper function
function validate(field) {
    // field must contain the string cool or fun
    if (!/cool|fun/.test(field)) {
        var validation = [
            {field: "address",message:"not valid"}
        ];
        return validation;
    } else {
        return null;
    }
}
// codehook
function beforePUT(req, res){
    log.debug("PUT: ",req.body);
    // call a helper function for custom validation
    var errors = validate(req.body.address);
    if (errors){
        res.end({"error": errors});
    } else {
        // add a calculated field
        req.body.tax = (req.body.salary * 0.33).toFixed(2); 
        res.end({"data": req.body});
    }
}

afterPUT

function afterPUT(req, res){
    log.debug("Inside after PUT, data is saved as", req.body);
        ...
    res.end();   
}

beforePOST

function beforePOST(req, res){
    log.debug("POST: ",req.body);
    ...
    res.end();
}

afterPOST

function afterPOST(req, res){
    log.debug("POST after: ",req.body);
    ...
    res.end();
}

beforeDELETE

function beforeDELETE(req, res){
    log.debug("Inside DELETE ",req.body);
    res.end();
}

Logging

As you seen in the examples above, you can log stuff from inside a codehook. The output can be seen in the Rest inspector. Use different log levels to better filter your log.

...
log.info("All is well");
log.debug("what's going on with", a, b, c);
log.error("Sorry, that broke: ", brokendata);
log.fatal("Yaiks, this should not happen");
...

Network calls from your codehook

A codehook function can perform network calls to other system using an the request API.

function afterPOST(req, res) {
    var opt = {
        method: 'GET',
        headers : {
            'User-Agent' : 'restdb.io (codehook)'
        },
        url: "http://fancyservice.io/api/foo"
    };
    request(opt, function(error, response, data){
        if(response.statusCode !== 200){
            log.error('Invalid Status Code Returned:', response.statusCode);
            res.end({error:[{message:"Unable to call fancyservice"}]});
            return
        }
        var json = JSON.parse(data);
        log.info("Got data: ",response.statusCode, json.length);
        // do something with json data
        ...
        res.end();
    });
}

// POST|PUT|DELETE
request({
    url: url,
    method: "POST | PUT | DELETE",
    json: true,
    headers: {
        "content-type": "application/json",
    },
    body: jsondata
    }, function(error, response, body) {
        ...
    });

Database calls from your codehook

db.get("/rest/customer", {"name": "Jane"}, {$max: 5}, function (err, results) {
    log.debug("Done get: ",err, results);
    ...
    res.end();
});

Background hooks

Records in the System_jobs collection are used to schedule tasks that invokes your codehooks.

Creating jobs in the System_jobs collection.

background codehooks

You can check the status of any current job in the System_log collection. It shows the res.end(...) output from a job. Any log.debug() statements can be inspected with the Rest inspector.

system log

Crontab expressions

A crontab expression is a special string with five components that builds an expression for a job schedule: E.g. run job each 10. th minute: */10 * * * *. Tip: let https://crontab.guru help you build your expression.

Example code:

function runJob(req, res) {
    log.debug("Inside a background job");
    ...
    res.end();
}

Warning

It's important to understand that a codehook function runs in a confined space with limited rights. It will not execute in the case of:

  • syntax errors
  • not explicitly returning with res.end()
  • not returning within x seconds
  • hacking attemts and other malicious code (may lead to blacklisting of account)