Apply Plugins

Introduction 

Transformers, Checkers and Hooks can be applied to any request.

In RESTHeart, not only documents but also dbs and collections (and files buckets, schema stores, etc.) have properties. Some properties are metadata, i.e. have a special meaning for RESTheart that controls its behavior.

You can use special metadata to apply plugins. Transformers and Checkers can also be applied programmatically.

Apply a Transformer via metadata

The metadata rts allows to declare transformers.

  • a transformer declared in the rts db property, gets executed to any requests that involves the db and its children resources (collections, documents, file buckets, schema stores, etc.).
  • a transformer declared in the rts collection property, gets executed to any requests that involves the collection and its documents.
{"name":<name>, "phase":<phase>, "scope":<scope>, "args":<args>}
Property
Description
Mandatory
name

The name of the transformer

Yes
phase

specifies to transform either the request or the response.

Valid values are REQUEST or RESPONSE

Yes
scope

Only applicable to RESPONSE transformers; with "scope": "THIS" the transformer is executed once on the whole response, with "scope":"CHILDREN" it is executed once per embedded document.

When "phase": "RESPONSE"
args arguments to be passed to the transformer. No

Apply a Transformer programmatically

Global Transformers can be defined programmatically instantiating GlobalTransformer objects:

    /**
     *
     * @param transformer
     * @param phase
     * @param scope
     * @param predicate transformer is applied only to requests that resolve
     * the predicate
     * @param args
     * @param confArgs
     */
    public GlobalTransformer(Transformer transformer,
            RequestContextPredicate predicate,
            RequestTransformer.PHASE phase,
            RequestTransformer.SCOPE scope,
            BsonValue args,
            BsonValue confArgs) {
        this.transformer = transformer;
        this.predicate = predicate;
        this.phase = phase;
        this.scope = scope;
        this.args = args;
        this.confArgs = confArgs;
    }

and adding them to the list TransformerHandler.getGlobalTransformers()

// a predicate that resolves GET /db/coll
RequestContextPredicate predicate = new RequestContextPredicate() {
            @Override
            public boolean resolve(HttpServerExchange hse, RequestContext context) {
                return context.isDb() && context.isGet();
            }
        };

// Let's use the predefined FilterTransformer to filter out properties from GET response
Transformer transformer = new FilterTransformer();

// FilterTransformer requires an array of properties to filter out as argument
BsonArray args = new BsonArray();
args.add(new BsonString("propToFilterOut"));

// if the checker requires configuration arguments, define them here
BsonDocument confArgs = null;

GlobalTransformer globalTransformer = new GlobalTransformer(
                transformer, 
                predicate,
                TransformerMetadata.PHASE.RESPONSE, 
                TransformerMetadata.SCOPE.CHILDREN, 
                args, 
                confArgs)

// finally add it to global checker list
TransformerHandler.getGlobalTransformers().add(globalTransformer);

You can use an Initializer to add Global Checkers and Global Transformers. An example can is AddBodyToWriteResponsesInitializer

Note that AddBodyToWriteResponsesInitializer is not enabled by default. To enabled it add enabled=true to its configuration.

Apply a Checker via metadata

The collection metadata property checkers allows to declare checkers to be applied to write requests.

checkers is an array of checker objects. A checker object has the following format:

{ "name": <checker_name>,"args": <arguments>, "skipNotSupported": <boolean> }
Property
Description
Mandatory
name

name of the checker.

Yes
args arguments to be passed to the checker no
skipNotSupported

if true, skip the checking if this checker does not support the request (Checker.doesSupportRequests())

no

Apply a Checker programmatically

Global Checkers can be defined programmatically instantiating GlobalChecker objects:

    /**
     * 
     * @param checker
     * @param predicate checker is applied only to requests that resolve
     * the predicate
     * @param skipNotSupported
     * @param args
     * @param confArgs 
     */
public GlobalChecker(Checker checker,
            RequestContextPredicate predicate,
            boolean skipNotSupported,
            BsonValue args,
            BsonValue confArgs)

and adding them to the list CheckerHandler.getGlobalCheckers()

// a predicate that resolves POST /db/coll and PUT /db/coll/docid requests
RequestContextPredicate predicate = new RequestContextPredicate() {
        @Override
        public boolean resolve(HttpServerExchange hse, RequestContext context) {
            return (context.isPost() && context.isCollection())
            || (context.isPut() && context.isDocument());
        }
    };

// Let's use the predefined ContentSizeChecker to limit write requests size
Checker checker = new ContentSizeChecker(); 

// ContentSizeChecker requires argument max, use 1024 Kbyte
BsonDocument args = new BsonDocument("max", new BsonInt32(1024*1024));

// if the checker requires configuration arguments, define them here
BsonDocument confArgs = null;

GlobalChecker globalChecker = new GlobalChecker(checker, predicate, true, args, confArgs);

// finally add it to global checker list
CheckHandler.getGlobalCheckers().add(globalChecker);

You can use an Initializer to add Global Checkers.

Apply an Hook via metadata

The collection metadata property hooks allows to declare the hooks to be applied to the requests involving the collection and its documents.

hooks is an array of objects with the following format:

{ "name": <hook_name>, "args": <arguments> }
Property
Description
Mandatory
name

name of the hook as defined in the configuration file.

Yes
args arguments to be passed to the hook. No

Apply an Hook programmatically

Global Hooks can be defined programmatically instantiating GlobalHook objects:

    /**
     * 
     * @param hook
     * @param predicate hook is applied only to requests that resolve
     * the predicate
     * @param args
     * @param confArgs 
     */
    public GlobalHook(Hook hook,
            RequestContextPredicate predicate,
            BsonValue args,
            BsonValue confArgs) {
        this.hook = hook;
        this.predicate = predicate;
        this.args = args;
        this.confArgs = confArgs;
    }

and adding them to the list HookHandler.getGlobalHooks()

// a predicate that always resolve
RequestContextPredicate predicate = new RequestContextPredicate() {
        @Override
        public boolean resolve(HttpServerExchange hse, RequestContext context) {
            return true;
        }
    };

// Let's use the predefined SnooperHook that logs old and new write requests 
Hook snooperHook = new SnooperHook(); 

// if the hook requires configuration arguments, define them here
BsonDocument args = null;

// if the hook requires configuration arguments, define them here
BsonDocument confArgs = null;

GlobalHook globalHook = new GlobalHook(hook, predicate, args, confArgs);

// finally add it to global hooks list
HookHandler.getGlobalHooks().add(globalHook);

You can use an Initializer to add Global Hook.