helidon-io / helidon

Java libraries for writing microservices
https://helidon.io
Apache License 2.0
3.52k stars 565 forks source link

Document how to customize MP server during startup #5925

Open romain-grecourt opened 1 year ago

romain-grecourt commented 1 year ago

The FAQ has an entry at https://github.com/helidon-io/helidon/wiki/FAQ#how-do-i-run-some-code-when-a-cdi-container-starts that describes how to run some code during startup.

We need to document what's in the FAQ combined with ServerCdiExtension ; as this is the only way to customize the underlying WebServer without configuration.

There are things that you can only do programmatically, e.g. handle bad requests for illegal characters in URI.

E.g.

@ApplicationScoped
public class BadRequestDirectHandler implements DirectHandler {

    private void beforeStart(
            @Observes
            @Priority(PLATFORM_AFTER)
            @Initialized(ApplicationScoped.class) Object ignoredEvent, ServerCdiExtension server) {

        server.serverBuilder().directHandler(this, EventType.BAD_REQUEST);
    }

    @Override
    public TransportResponse handle(TransportRequest request,
                                    EventType eventType,
                                    Http.ResponseStatus defaultStatus,
                                    Throwable throwable) {

        // Special handling goes here...
        return handle(request, eventType, defaultStatus, throwable.getMessage());
    }

    @Override
    public TransportResponse handle(TransportRequest request,
                                    EventType eventType,
                                    Http.ResponseStatus defaultStatus,
                                    String message) {

        TransportResponse.Builder builder = TransportResponse.builder().status(defaultStatus);
        if (!message.isEmpty()) {
            builder.entity(message);
        }
        return builder.build();
    }
}
romain-grecourt commented 2 days ago

The direct handlers have been removed in v4, they were design to handle events pre Helidon routing, in Netty related code.

In v4 you can use normal error handlers, so the example above can be converted to something like this:

@ApplicationScoped
class URISyntaxHandler implements ErrorHandler<MyException> {

    @Override
    public void handle(ServerRequest req, ServerResponse res, MyException ex) {
        if (ex.getCause() instanceof MyNestedException) {
            res.status(Status.BAD_REQUEST_400).send("Invalid URI");
        } else {
            res.next();
        }
    }

    @SuppressWarnings("ALL")
    private void beforeStart(
            @Observes
            @Priority(PLATFORM_AFTER)
            @Initialized(ApplicationScoped.class) Object ignoredEvent, ServerCdiExtension server) {

        server.serverRoutingBuilder().error(MyException.class, this);
    }
}