Skip to content

Instantly share code, notes, and snippets.

@tjquinno
Last active April 23, 2020 19:22
Show Gist options
  • Save tjquinno/537452625c9f2f732a53997282343524 to your computer and use it in GitHub Desktop.
Save tjquinno/537452625c9f2f732a53997282343524 to your computer and use it in GitHub Desktop.
CORS for Helidon Built-in Services

Adding CORS to built-in Helidon services

We are adding CORS support to the existing built-in services for metrics, health, and OpenAPI. Users have asked specifically for Helidon OpenAPI to spuport CORS because of applications or sites like Swagger U/I. It seems reasonable that there might be sites or apps that act as front ends for the metrics or health information for one or more apps.

By default metrics, health, and OpenAPI will support CORS with these settings:

   allow-methods: ["GET", "HEAD", "OPTIONS"]

with the other settings defaulted. This is equivalent to:

   enabled: true
   allow-origins: ["*"]
   allow-methods: ["GET", "HEAD", "OPTIONS"]
   allow-headers: ["*"]
   allow-credentials: false
   max-age: 3600

User control

The user can override the default CORS configuration for a service by adding a cors entry to the existing service configuration. For example:

metrics:
  cors:
    allow-methods: ["*"]
    ...

The following turns off CORS support entirely for health:

health:
  cors:
    enabled: false

Changes in Helidon code

Each xxxSupport service has a builder with a config(Config) method from which they extract service-specific information and set attributes in the builder. Here are the coding changes to OpenAPISupport to add CORS support, as an example for all the CORS-enabled services:

In the builder

  • Add the field private CrossOriginConfig crossOriginConfig = null;
  • In config(Config) add logic to extract the CORS config node from the service's config and save it:
config.get(CorsEnabledServiceHelper.CORS_CONFIG_KEY) // standardize on "cors" for built-in services
            .as(CrossOriginConfig::create)
            .ifPresent(this::crossOriginConfig);
  • Add a setter for the crossOriginConfig for use from the config method or from other code:
public Builder crossOriginConfig(CrossOriginConfig crossOriginConfig) {
    Objects.requireNonNull(crossOriginConfig, "CrossOriginConfig must be non-null");
    this.crossOriginConfig = crossOriginConfig;
    return this;
}

In the service itself

  • Add the field private final CorsEnabledServiceHelper corsEnabledServiceHelper;
  • In the constructor OpenAPI(Builder builder) add
corsEnabledServiceHelper = CorsEnabledServiceHelper.create(
        "OpenAPI",  // for logging
        builder.crossOriginConfig;
  • In update (or, often configureEndpoint which update invokes):
rules.get(JsonSupport.create())
     .any(webContext, corsEnabledServiceHelper.processor()) // this is new
     .get(webContext, this::prepareResponse);

The processor returned by the helper and used in the any invocation is a CorsSupport instance, set up according to the config used to create it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment