ContextPathConfig.java

package se.jobtechdev.personaldatagateway.api.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import se.jobtechdev.personaldatagateway.api.exception.InvalidSemverFormat;

import java.util.regex.Pattern;

@Configuration
public class ContextPathConfig {
  private static final Logger logger = LoggerFactory.getLogger(ContextPathConfig.class);

  // @see https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
  private static final String SEMVER_PATTERN =
      // Start of line
      "^"
          // Version Code
          + "(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)"
          // Optional pre-release segment
          + "(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)"
          // Extra pre-release segment (dot delimited, maximum 10 extra pre-release segments to
          // avoid potential overflow due to backtracking)...
          + "(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)){0,10}))?"
          // Optional build segment
          + "(?:\\+([0-9a-zA-Z-]+"
          // Extra build segment (dot delimited, maximum 10 extra build segments to avoid potential
          // overflow due to backtracking)...
          + "(?:\\.[0-9a-zA-Z-]+){0,10}))?"
          // End of line
          + "$";

  private static final Pattern pattern = Pattern.compile(SEMVER_PATTERN);

  @Bean
  public WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> webServerFactoryCustomizer(
      @Value("${api.spec.version}") String apiSpecVersion,
      @Value("${server.servlet.context-path:#{''}}") String serverServletContextPath) {

    final var matcher = pattern.matcher(apiSpecVersion);

    if (!matcher.matches()) {
      throw new InvalidSemverFormat(apiSpecVersion);
    }

    final var major = matcher.group(1);
    logger.info("API Spec major version: {}", major);
    if (serverServletContextPath.isEmpty()) {
      return factory -> factory.setContextPath("/v" + major);
    } else {
      return factory -> factory.setContextPath(serverServletContextPath);
    }
  }
}