Request Hooks

Introduction

Request Hooks allow to execute custom code after a request completes.

For example, request hooks can be used:

  • to send a confirmation email when a user registers 
  • to send push notifications when a resource is updated so that its properties satisfy a given condition.

The hooks collection metadata

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.

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

How to develop an Hook

Request Hooks are implemented in java and declared in the RESTHeart configuration file; once the are configured, they can be bound to collections via the hooks collection metadata.

Of course, the class(es) that implements the Hook must be added to the java classpath. See (How to package custom code)[/learn/custom-code-packaging-howto] for more information.

For example, if the hook is packaged in the myhook.jar file, start RESTHeart with the following command:

$ java -server -classpath restheart.jar:myhook.jar org.restheart.Bootstrapper restheart.yml

Hooks are developed implementing the java interface org.restheart.metadata.hooks.Hook.

To add a dependency on RESTHeart using Maven, use the following:

<dependency>
    <groupId>org.restheart</groupId>
    <artifactId>restheart</artifactId>
    <version>3.0.2</version>
</dependency>

The Hook interface requires to implement the following interface:

public interface Hook {
    /**
     *
     * @param exchange the server exchange
     * @param context the request context
     * @param args the args sepcified in the collection metadata via args property
     * @return true if completed successfully
     */
    default boolean hook(
            HttpServerExchange exchange,
            RequestContext context,
            BsonValue args) {
        return hook(exchange, context, args, null);
    }
        

    /**
     *
     * @param exchange the server exchange
     * @param context the request context
     * @param args the args sepcified in the collection metadata via args property
     * @param confArgs args specified in the configuration file via args property
     * @return true if completed successfully
     */
    default boolean hook(
            HttpServerExchange exchange,
            RequestContext context,
            BsonValue args,
            BsonDocument confArgs) {
        return hook(exchange, context, args);
    }

    /**
     *
     * @param context
     * @return true if the hook supports the requests
     */
    boolean doesSupportRequests(RequestContext context);
}

The method doesSupportRequests() determines if the hook() method should be against the RequestContext object that encapsulates all information about the request.

For instance, the following implementation returns true if the request actually created a document (either POSTing the collection or PUTing the document):

@Override
public boolean doesSupportRequests(RequestContext rc) {
    if (rc.getDbOperationResult() == null) {
        return false;
    }

    int status = rc.getDbOperationResult().getHttpCode();

    return (status == HttpStatus.SC_CREATED
            && (rc.isCollection() && rc.isPost()
            || rc.isDocument()  && rc.isPut());
}

Note the following useful RequestContext getters:



getDbOperationResult() returns the OperationResult object that encapsulates the information about the MongoDB operation, including the resource status (properties) before and after the request execution.
getType() returns the request resource type, e.g. DOCUMENT, COLLECTION, etc.
getMethod() returns the request method, e.g. GET, PUT, POST, PATCH, DELETE, etc.

The hook() method is where the custom logic is defined.

It has four arguments:

  • the HttpServerExchange and the RequestContext that give information about the request
  • the optional json args object specified in the hook collection metadata.
  • the optional json confArgs object specified in the definition of the hook in the configuration file

How to declare an Hook in the configuration file

The metadata-named-singletons section of the configuration file defines, among others, the hooks group: here hook implementation classes can be given names that can be used in the hooks collection metadata property.

The following is the default hooks configuration that declares the example snooper hook(that just logs resource status before and after request db operation execution).

metadata-named-singletons:
    - group: hooks
      interface: org.restheart.metadata.hooks.Hook
      singletons:
        - name: snooper
          class: org.restheart.metadata.hooks.SnooperHook