# About Middlewares

Middleware functions are functions that have access to the request Context ("ctx"), the configuration of the Action ("config"), and the next Action (or Middleware) function in the application’s request-response cycle ("action"): The "config" contains all annotations of the Action, converted to a Tree (~= JSON) object. Middleware functions can perform the following tasks:

  • Execute any code.
  • Make changes to the request and the response objects.
  • End the request-response cycle.
  • Call the next local or remote Action or Middleware in the stack.
public class MyMiddleware extends Middleware {

    public Action install(Action action, Tree config) {

        // Create new "Action" or return "null", this is decided by
        // the "config" which contains the parameters of the original Action.
        // If you return "null", you won't install Middleware for the Action.

        return new Action() {
            public Object handler(Context ctx) throws Exception {

                // --- FUNCTIONS BEFORE CALLING THE ACTION ---

                // Do nothig, just invoke next Middleware or Action
                Object rsp = action.handler(ctx);

                // --- FUNCTIONS AFTER CALLING THE ACTION ---

                // Return the response of the Action
                return rsp;
            }
        };
    }
}

Use the "use" function of ServiceBroker to install the Middleware:

broker.use(new MyMiddleware());

Middlewares is executed in reverse order as they are added to ServiceBroker:

broker.use(new LastMiddleware()); // Installed and/or executed LAST
broker.use(new ThirdMiddleware());
broker.use(new SecondMiddleware());
broker.use(new FirstMiddleware()); // Installed and/or executed FIRST
Calling flow

# Example of Middleware-based pre-processing

In Java-based Moleculer, it is easiest to configure Actions with annotations. The following code snippet creates an annotation to assign Roles to Actions:

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.TYPE })
public @interface RequiredRoles {

    String[] value() default { "admin" };

}

Annotations can be added to the Actions as follows:



 




 






public class CheckedService extends Service {

    @RequiredRoles("admin")
    public Action adminAction = ctx -> {
        // ...
    };

    @RequiredRoles({"user", "admin"})
    public Action userAction = ctx -> {
        // ...
    };

}

Middleware can access the list of "RequiredRoles" via the "config" object:

public class AccessControllerMiddleware extends Middleware {

    @Override
    public Action install(Action action, Tree config) {

        // Does the Action have "RequiredRoles" annotation?
        Tree requiredRoles = config.get("requiredRoles");
        if (requiredRoles == null) {

            // If there is no "RequiredRoles", we won't install anything
            return null;
        }

        // Install new "layer" on top of the Action
        return new Action() {

            @Override
            public Object handler(Context ctx) throws Exception {

                // Role check with some control function
                if (!userInRole(ctx, requiredRoles)) {
                    throw new SecurityException("Access denied!");
                }

                // Access is allowed
                return action.handler(ctx);
            }
        };
    }

}

Finally install the Middleware using the "use" function of ServiceBroker:

broker.use(new AccessControllerMiddleware());

# Caching the response of Actions

Among many other uses, Middleware is used to cache the response of Action. Cacher Middleware is an abstract class that uses request input data as a key to store responses in a cache. The actual implementation of the Cacher can be local or distributed. Cacher Middleware is automatically added to ServiceBroker at startup.
Read more about caching.

There is another kind of middleware in the Moleculer Framework; the HttpMiddleware. An HTTP Middleware is similar to Middleware, but HTTP Middleware processes HTTP requests instead of internal Action calls.
Read more about HTTP Middlewares

If you are interested in compression or encryption, you should not do it with Middleware, but with Serializers.