Skip to the content.

Handlers

A handler implements the business logic of the API. Listeners forwarads requests to a handler for processing. A handler may register the API’s of other handlers on it’s protocol, as a proxy-handler or simply define its own API.

Implementing a handler

The deployment of a handler requires at least a CoreService, see listeners for a set of listeners that are included in the framework.

// The address is used by the listener to determine where to mount the handler.
// the REST handler would mount this at "/cats" for example.
@Role(PUBLIC)
@Address("cats")
public class CatHandler implements CoreHandler {
    // this example uses the annotated protocol, see the Protocol chapter for more.
    private Protocol<Request> protocol = new Protocol<>(this);

    // defines an API endpoint reachable at "/cats/meow" when using the RestListener.
    @Api
    public void meow(CatRequest request) {
        MeowModel meow = request.getMeow();
        
        if (meow.getLoudness() < 100) {
            request.write("meow complete.");
        } else {
            request.fail(new MeowLoudnessTooHighException());
        }
    }

    @Override
    public void init(CoreContext core) {
        // optional override: if context is required.    
    }
    
    @Override
    public void start(Future<Void> future) {
        // optional override: if async setup is required.    
    }

    @Override
    public void stop(Future<Void> future) {
        // optional override: if cleanup is required.    
    }
    
    @Override
    public void handle(Request request) {
        protocol.process(new CatRequest(request));
    }
}

To simplify dealing with request data we can wrap the request body in a model class. If we use the request.data() only a JsonObject API will be available.

public class CatRequest implements RequestWrapper() {
    private Request request;
    
    // the original request is required for wrapping.
    public CatRequest(Request request) {
        this.request = request;
    }
    
    public MeowModel getMeow() {
        // this can also be done in the handler without a wrapper class.
        return Serializer.unpack(request.data(), MeowModel.class);    
    }
    
    @Override
    public Request request() {
        return request;
    }
}

Another example of a minimal handler without request wrapping,

@Role(PUBLIC)
@Address("cats")
public class Cathandler implements CoreHandler {
    private Protocol<Request> protcol = new Protocol<>(this);
    
    @Api
    public void meow(Request request) {
        int loudness = request.data().getInteger("loudness");
        request.write("meow in progress at " + loudness + " decibels.");
    }
    
    @Override
    public void handle(Request request) {
        protocol.process(request);
    }
}

Deploying a handler

Deploying a handler requires a running SystemContext, example

core.handler(Cathandler::new);

When a handler is deployed using the handler method on the context the listener will always default to ClusterListener.

To deploy the handler on a specific listener the following can be used,

core.listener(() -> new RestListener().handler(new CatHandler()));

This will use the default ListenerSettings for the RestListener. To change the listening port settings can be set on the listener instance.