Content

Overview

Helidon provides a MicroProfile server implementation (io.helidon.microprofile.server.Server) that encapsulates the Helidon WebServer.

Maven-Coordinates

To enable MicroProfile Server add the helidon-microprofile-core bundle dependency to your project’s pom.xml (see Managing Dependencies).

<dependency>
    <groupId>io.helidon.microprofile.bundles</groupId>
    <artifactId>helidon-microprofile-core</artifactId>
</dependency>
Copied

MicroProfile Server is already included in the bundle.

If full control over the dependencies is required, and you want to minimize the quantity of the dependencies - Helidon MicroProfile Server should be used. In this case the following dependencies should be included in your project’s pom.xml:

<dependency>
    <groupId>io.helidon.microprofile.server</groupId>
    <artifactId>helidon-microprofile-server</artifactId>
</dependency>
Copied

Usage

Helidon Microprofile Server is used to collect and deploy JAX-RS application(s). When starting Helidon MP, it is recommended to use the io.helidon.Main main class, which will take care of starting Helidon. CDI will then discover all extensions, including the Server extension and start it.

See the Helidon MP Quickstart example. Note that the server lifecycle is bound to CDI.

Usage of the io.helidon.microprofile.server.Server API is discouraged, as Helidon MP uses convention to discover and configure features, which makes the applications easier to understand and maintain.

API

The following table provides a brief description of routing annotations, including its parameters. More information in Configuring a WebServer route section.

AnnotationDescription
@RoutingName(
    value = ""
    required = false
)
Binds a JAX-RS Application or Helidon Service to a specific (named) routing on WebServer.The routing should have a corresponding named socket configured on the WebServer to run the routing on.
@RoutingPath("/path")
Path of a Helidon Service to register with routing.

Configuration

By default, the server uses the MicroProfile Config, but you may also want to use Helidon configuration.

In this example, the configuration is in a file, and it includes Helidon configuration options.

Configuration reference:

Type: io.helidon.webserver.WebServer

This is a standalone configuration type, prefix from configuration root: server

Configuration options

Optional configuration options
keytypedefault valuedescription
backlog

int

1024

Accept backlog.

@return backlog
connection-config 

Configuration of a connection (established from client against our server).

@return connection configuration
connection-options 

Options for connections accepted by this listener. This is not used to setup server connection.

@return socket options
content-encoding 

Configure the listener specific io.helidon.http.encoding.ContentEncodingContext. This method discards all previously registered ContentEncodingContext. If no content encoding context is registered, content encoding context of the webserver would be used.

@return content encoding context
features 

Server features allow customization of the server, listeners, or routings.

@return server features
host

string

0.0.0.0

Host of the default socket. Defaults to all host addresses (0.0.0.0).

@return host address to listen on (for the default socket)
idle-connection-period

Duration

PT2M

How often should we check for #idleConnectionTimeout(). Defaults to PT2M (2 minutes).

@return period of checking for idle connections
idle-connection-timeout

Duration

PT5M

How long should we wait before closing a connection that has no traffic on it. Defaults to PT5M (5 minutes). Note that the timestamp is refreshed max. once per second, so this setting would be useless if configured for shorter periods of time (also not a very good support for connection keep alive, if the connections are killed so soon anyway).

@return timeout of idle connections
max-concurrent-requests

int

-1

Limits the number of requests that can be executed at the same time (the number of active virtual threads of requests). Defaults to -1, meaning "unlimited" - what the system allows. Also make sure that this number is higher than the expected time it takes to handle a single request in your application, as otherwise you may stop in-progress requests.

@return number of requests that can be processed on this listener, regardless of protocol
max-in-memory-entity

int

131072

If the entity is expected to be smaller that this number of bytes, it would be buffered in memory to optimize performance when writing it. If bigger, streaming will be used.

Note that for some entity types we cannot use streaming, as they are already fully in memory (String, byte[]), for such
cases, this option is ignored.
Default is 128Kb.
@return maximal number of bytes to buffer in memory for supported writers
max-payload-size

long

-1

Maximal number of bytes an entity may have. If io.helidon.http.HeaderNames#CONTENT_LENGTH is used, this is checked immediately, if io.helidon.http.HeaderValues#TRANSFER_ENCODING_CHUNKED is used, we will fail when the number of bytes read would exceed the max payload size. Defaults to unlimited (-1).

@return maximal number of bytes of entity
max-tcp-connections

int

-1

Limits the number of connections that can be opened at a single point in time. Defaults to -1, meaning "unlimited" - what the system allows.

@return number of TCP connections that can be opened to this listener, regardless of protocol
media-context 

Configure the listener specific io.helidon.http.media.MediaContext. This method discards all previously registered MediaContext. If no media context is registered, media context of the webserver would be used.

@return media context
name

string

@default

Name of this socket. Defaults to @default. Must be defined if more than one socket is needed.

@return name of the socket
port

int

0

Port of the default socket. If configured to 0 (the default), server starts on a random port.

@return port to listen on (for the default socket)
protocols

io.helidon.webserver.spi.ProtocolConfig[] (service provider interface)

 

Configuration of protocols. This may be either protocol selectors, or protocol upgraders from HTTP/1.1. As the order is not important (providers are ordered by weight by default), we can use a configuration as an object, such as: <pre> protocols: providers: http_1_1: max-prologue-length: 8192 http_2: max-frame-size: 4096 websocket: …​. </pre>

@return all defined protocol configurations, loaded from service loader by default
receive-buffer-size

int

 

Listener receive buffer size.

@return buffer size in bytes
shutdown-grace-period

Duration

PT0.5S

Grace period in ISO 8601 duration format to allow running tasks to complete before listener’s shutdown. Default is 500 milliseconds. Configuration file values example: PT0.5S, PT2S.

@return grace period
shutdown-hook

boolean

true

When true the webserver registers a shutdown hook with the JVM Runtime.

Defaults to true. Set this to false such that a shutdown hook is not registered.
@return whether to register a shutdown hook
sockets 

Socket configurations. Note that socket named WebServer#DEFAULT_SOCKET_NAME cannot be used, configure the values on the server directly.

@return map of listener configurations, except for the default one
tls 

Listener TLS configuration.

@return tls of this configuration
write-buffer-size

int

512

Initial buffer size in bytes of java.io.BufferedOutputStream created internally to write data to a socket connection. Default is 512.

@return initial buffer size used for writing
write-queue-length

int

0

Number of buffers queued for write operations.

@return maximal number of queued writes, defaults to 0

Examples

Access Log

Access logging in Helidon is done by a dedicated module that can be added to Maven and configured.

To enable Access logging add the following dependency to project’s pom.xml:

<dependency>
    <groupId>io.helidon.microprofile</groupId>
    <artifactId>helidon-microprofile-access-log</artifactId>
</dependency>
Copied

Configuring Access Log in a configuration file

Access log can be configured as follows:

Access Log configuration file
server.port=8080
server.host=0.0.0.0
server.features.access-log.format=helidon
Copied

AccessLogFeature (webserver.accesslog) Configuration

Type: io.helidon.webserver.accesslog.AccessLogFeature

Config key
access-log
Copied

This type provides the following service implementations:

  • io.helidon.webserver.spi.ServerFeatureProvider

Configuration options

Optional configuration options
keytypedefault valuedescription
enabled

boolean

true

Whether this feature will be enabled.

@return whether enabled
format

string

 

The format for log entries (similar to the Apache LogFormat). <table class="config"> <caption>Log format elements</caption> <tr> <td>%h</td> <td>IP address of the remote host</td> <td>HostLogEntry</td> </tr> <tr> <td>%l</td> <td>The client identity. This is always undefined in Helidon.</td> <td>UserIdLogEntry</td> </tr> <tr> <td>%u</td> <td>User ID as asserted by Helidon Security.</td> <td>UserLogEntry</td> </tr> <tr> <td>%t</td> <td>The timestamp</td> <td>TimestampLogEntry</td> </tr> <tr> <td>%r</td> <td>The request line ("GET /favicon.ico HTTP/1.0")</td> <td>RequestLineLogEntry</td> </tr> <tr> <td>%s</td> <td>The status code returned to the client</td> <td>StatusLogEntry</td> </tr> <tr> <td>%b</td> <td>The entity size in bytes</td> <td>SizeLogEntry</td> </tr> <tr> <td>%D</td> <td>The time taken in microseconds (start of request until last byte written)</td> <td>TimeTakenLogEntry</td> </tr> <tr> <td>%T</td> <td>The time taken in seconds (start of request until last byte written), integer</td> <td>TimeTakenLogEntry</td> </tr> <tr> <td>%{header-name}i</td> <td>Value of header header-name</td> <td>HeaderLogEntry</td> </tr> </table>

@return format string, such as `%h %l %u %t %r %b %{Referer`i}
logger-name

string

io.helidon.webserver.AccessLog

Name of the logger used to obtain access log logger from System#getLogger(String). Defaults to AccessLogFeature#DEFAULT_LOGGER_NAME.

@return name of the logger to use
sockets

string[]

 

List of sockets to register this feature on. If empty, it would get registered on all sockets. The logger used will have the expected logger with a suffix of the socket name.

@return socket names to register on, defaults to empty (all available sockets)
weight

double

1000.0

Weight of the access log feature. We need to log access for anything happening on the server, so weight is high: io.helidon.webserver.accesslog.AccessLogFeature#WEIGHT.

@return weight of the feature

Configuring TLS

Helidon MP also supports custom TLS configuration.

You can set the following properties:

  • Server truststore

    • Keystore with trusted certificates

  • Private key and certificate

    • Server certificate which will be used in TLS handshake

META-INF/microprofile-config.properties - Server configuration
#Truststore setup
server.tls.trust.keystore.resource.resource-path=server.p12
server.tls.trust.keystore.passphrase=password
server.tls.trust.keystore.trust-store=true

#Keystore with private key and server certificate
server.tls.private-key.keystore.resource.resource-path=server.p12
server.tls.private-key.keystore.passphrase=password
Copied

Or the same configuration done in application.yaml file.

application.yaml - Server configuration
server:
  tls:
    #Truststore setup
    trust:
      keystore:
        passphrase: "password"
        trust-store: true
        resource:
          resource-path: "keystore.p12"
    #Keystore with private key and server certificate
    private-key:
      keystore:
        passphrase: "password"
        resource:
          resource-path: "keystore.p12"
Copied

Configuring additional ports

Helidon MP can expose multiple ports, with the following limitations:

  • The default port is the port that serves your application (JAX-RS applications and resources)

  • Other ports (in this example we configure one "admin" port) can be assigned endpoints that are exposed by Helidon components, currently supported by MP Health and MP Metrics

For this example, we will use a YAML file:

  • The port 7011 is the default port and will serve your application

  • The port 8011 is named "admin" (this is an arbitrary name)

  • MP Metrics are configured to use the "admin" port through the routing configuration (reference is by name)

  • MP Health is configured the same way to reference the "admin" port

application.yaml - Server configuration
server:
  port: 7011
  host: "some.host"
  sockets:
    admin:
      port: 8011
      bind-address: "some.host"

metrics:
  routing: "admin"

health:
  routing: "admin"
Copied

Configuring A WebServer Route [[

Helidon MP Server will pick up CDI beans that implement the io.helidon.webserver.HttpService interface and configure them with the underlying WebServer.

This allows configuration of WebServer routes to run alongside a JAX-RS application.

The bean is expected to be either ApplicationScoped or Dependent and will be requested only once during the boot of the Server.

The bean will support injection of ApplicationScoped and Dependent scoped beans. You cannot inject RequestScoped beans. Please use WebServer features to handle request related objects.

Customizing the HTTP service

The service can be customized using annotations and/or configuration to be

  • registered on a specific path

  • registered with a named routing

Assigning an HTTP service to named ports

Helidon has the concept of named routing. These correspond to the named ports configured with WebServer.

You can assign an HTTP service to a named routing (and as a result to a named port) using either an annotation or configuration (or both to override the value from annotation).

Annotation @RoutingName

You can annotate a service bean with this annotation to assign it to a specific named routing, that is (most likely) going to be bound to a specific port.

The annotation has two attributes: - value that defines the routing name - required to mark that the routing name MUST be configured in Helidon server

@RoutingName example
@ApplicationScoped
@RoutingName(value = "admin", required = true)
@RoutingPath("/admin")
public class AdminService implements HttpService {
    @Override
    public void routing(HttpRules rules) {
        // ...
    }
}
Copied

The example above will be bound to admin routing (and port) and will fail if such a port is not configured.

Configuration override of routing name

For each service bean you can define the routing name and its required flag by specifying a configuration option bean-class-name.routing-name.name and bean-class-name.routing-name.required. For service beans produced with producer method replace bean-class-name with class-name.producer-method-name.

Example (YAML) configuration for a service bean io.helidon.examples.AdminService that changes the routing name to management and its required flag to false:

io.helidon.examples.AdminService:
  routing-name:
    name: "management"
    required: false
Copied

Configuring an HTTP service path

Each service is registered on a path. If none is configured, then the service would be configured on the root path.

You can configure service path using an annotation or configuration (or both to override value from annotation)

Annotation @RoutingPath

You can configure @RoutingPath to define the path a service is registered on.

Configuration override of routing path

For each HTTP service class you can define the routing path by specifying a configuration option class-name.routing-path.path. The routing-path configuration can be applied to Jax-RS application. See Jakarta REST Application for more information.

Example (YAML) configuration for a class io.helidon.example.AdminService that changes the routing path to /management:

io.helidon.examples.AdminService:
  routing-path:
    path: "/management"
Copied

Serving Static Content

META-INF/microprofile-config.properties - File system static content
# Location of content on file system
server.static.path.location=/var/www/html
# default is index.html
server.static.path.welcome=resource.html
# static content path - default is "/"
# server.static.path.context=/static-file
Copied
META-INF/microprofile-config.properties - Classpath static content
# src/main/resources/WEB in your source tree
server.static.classpath.location=/WEB
# default is index.html
server.static.classpath.welcome=resource.html
# static content path - default is "/"
# server.static.classpath.context=/static-cp
Copied

Example configuration of routing

A full configuration example (YAML):

server:
  port: 8080
  sockets:
   management:
   port: 8090

io.helidon.examples.AdminApplication:
  routing-name:
    name: "management"
    required: true
  routing-path:
    path: "/management"
Copied

Using Requested URI Discovery

Proxies and reverse proxies between an HTTP client and your Helidon application mask important information (for example Host header, originating IP address, protocol) about the request the client sent. Fortunately, many of these intermediary network nodes set or update either the standard HTTP Forwarded header or the non-standard X-Forwarded-* family of headers to preserve information about the original client request.

Helidon’s requested URI discovery feature allows your application—​and Helidon itself—​to reconstruct information about the original request using the Forwarded header and the X-Forwarded-* family of headers.

When you prepare the connections in your server you can include the following optional requested URI discovery settings:

  • enabled or disabled

  • which type or types of requested URI discovery to use:

    • FORWARDED - uses the Forwarded header

    • X_FORWARDED - uses the X-Forwarded-* headers

    • HOST - uses the Host header

  • what intermediate nodes to trust

When your application receives a request Helidon iterates through the discovery types you set up for the receiving connection, gathering information from the corresponding header(s) for that type. If the request does not have the corresponding header(s), or your settings do not trust the intermediate nodes reflected in those headers, then Helidon tries the next discovery type you set up. Helidon uses the HOST discovery type if you do not set up discovery yourself or if, for a particular request, it cannot assemble the request information using any discovery type you did set up for the socket.

Setting Up Requested URI Discovery

You can use configuration to set up the requested URI discovery behavior.

Configuring Request URI Discovery (properties format)
server.port=8080
server.requested-uri-discovery.types=FORWARDED,X_FORWARDED
server.requested-uri-discovery.trusted-proxies.allow.pattern=lb.*\\.mycorp\\.com
server.requested-uri-discovery.trusted-proxies.deny.exact=lbtest.mycorp.com
Copied

This example might apply if mycorp.com had trusted load balancers named lbxxx.mycorp.com except for an untrusted test load balancer lbtest.mycorp.com.

Obtaining the Requested URI Information

Helidon makes the requested URI information available as a property in the request context:

Retrieving Requested URI Information
public class MyFilter implements ContainerRequestFilter {

    @Override
    public void filter(ContainerRequestContext requestContext) {
        UriInfo uriInfo = (UriInfo) requestContext.getProperty("io.helidon.jaxrs.requested-uri");
        // ...
    }
}
Copied

See the UriInfo JavaDoc for more information.

The requestContext.getUriInfo() method returns the Jakarta RESTful web services UriInfo object, not the Helidon-provided requested URI information UriInfo record.

Reference