mscharhag, Programming and Stuff;

A blog about programming and software development topics, mostly focused on Java technologies including Java EE, Spring and Grails.

  • Thursday, 23 January, 2020

    Creating an API Gateway with Zuul and Spring Boot

    Introduction

    When working with micro services it is common to have unified access-point to your system (also called API Gateway). Consumers only talk with the API Gateway and not with the services directly. This hides the fact that your system is composed out of multiple smaller services. The API Gateway also helps solving common challenges like authentication, managing cross-origin resource sharing (CORS) or request throttling.

    Zuul is a JVM-based API Gateway developed and open-sourced by Netflix. In this post we will create a small Spring application that includes a zuul proxy for routing requests to other services.

    Enabling zuul proxy

    To use zuul in a project we have to add the spring-cloud-starter-netflix-zuul dependency. If we want to use the spring zuul actuator endpoint (more on this later), we also need to add the spring-boot-starter-actuator dependency.

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
    </dependency>
    
    <!-- optional -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    

    Next we have to enable the zuul proxy using @EnableZuulProxy in our spring boot application class (or any other spring @Configuration class)

    @SpringBootApplication
    @EnableZuulProxy
    public class ZuulDemoApplication {
        ...
    }
    

    Now we can start configuring our routes.

    Configuring routes

    Routes describe how incoming requests should be routed by zuul. To configure zuul routes we only have to add a few lines to our spring boot application.yml (or application.properties) file:

    application.yml:

    zuul:
      routes:
        users:
          path: /users/**
          url: https://users.myapi.com
        projects:
          path: /projects/**
          url: https://projects.myapi.com
    

    Here we define the routes for two endpoints: /users and /projects: Requests to /users will be routed to https://users.myapi.com while requests to /projects are routed to https://projects.myapi.com.

    Assume we start this example application locally and send a GET request to http://localhost:8080/users/john. This request matches the zuul route /users/** so zuul will forward the request to https://users.myapi.com/john.

    When using a service registry (like Eureka) we can alternatively configure a service id instead of an url:

    zuul:
      routes:
        users:
          path: /users/**
          serviceId: user_service
    

    Another useful option is sensitiveHeaders, which allows us to remove headers before the request is routed to another service. This can be used to avoid leaking of sensitive headers into external servers (e.g. security tokens or session ids).

    zuul:
      routes:
        users:
          path: /users/**
          url: https://users.myapi.com      
          sensitiveHeaders: Cookie,Set-Cookie,Authorization
    

    Note that the shown example headers (Cookie,Set-Cookie,Authorization) are the default value of the sensitiveHeaders property. So these headers will not be passed, even if sensitiveHeaders is not specified.

    Request / Response modification with filters

    We can customize zuul routing using filters. To create a zuul filter we create a new spring bean (marked with @Component) which extends from ZuulFilter:

    @Component
    public class MyFilter extends ZuulFilter {
    
        @Override
        public String filterType() {
            return FilterConstants.PRE_TYPE;
        }
    
        @Override
        public int filterOrder() {
            return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1;
        }
    
        @Override
        public boolean shouldFilter() {
            return true;
        }
    
        @Override
        public Object run() {
            RequestContext context = RequestContext.getCurrentContext();
            context.addZuulRequestHeader("my-auth-token", "s3cret");
            return null;
        }
    }
    

    ZuulFilter requires the definition of four methods:

    • Within filterType() we define that our filter should run before (PRE_TYPE) the actual routing. If we want to modify the response of the service before it is send back to the client, we can return POST_TYPE here.
    • With filterOrder() we can influence to order of filter execution
    • shouldFilter() indicates if this filter should be executed (= calling the run() method)
    • in run() we define the actual filter logic. Here we add a simple header named my-auth-token to the request that is routed to another service.

    Filters allow us to modify the request before it is send to the specified service or to modify the response of the service before it is send back to the client.

    Actuator endpoint

    Spring cloud zuul exposed an additional Spring Boot actuator endpoint. To use this feature we need to have spring-boot-starter-actuator in the classpath.

    By default the actuator endpoint is disabled. Within application.yml we enable specific actuator endpoints using the management.endpoints.web.exposure.include property:

    management:
      endpoints:
        web:
          exposure:
            include: '*'
    

    Here we simply enable all actuator endpoints. More detailed configuration options can be found in the Spring Boot actuator documentation.

    After enabling the zuul actuator endpoint we can send a GET request to http://localhost:8080/actuator/routes to get a list of all configured routes.

    An example response might look like this:

    {
        "/users/**":"https://users.myapi.com",
        "/projects/**":"project_service"
    }
    

    Summary

    With Spring cloud you can easliy integrate a zuul proxy in your application. This allows you the configuration of routes in .yml or .properties files. Routing behaviour can be customized with Filters.

    More details on spring's support for zuul can be found in the offical spring cloud zuul documentation. As always you can find the examples shown in this post on GitHub.

  • Monday, 6 January, 2020

    Method parameter validation with Spring and JSR 303

    Spring provides an easy way to validate method parameters using JSR 303 bean validation. In this post we will see how to use this feature.

    Setup

    First we need to add support for method parameter validation by creating a MethodValidationPostProcessor bean:

    @Configuration
    public class MyConfiguration {
        @Bean
        public MethodValidationPostProcessor methodValidationPostProcessor() {
            return new MethodValidationPostProcessor();
        }
    }
    

    Validating method parameters

    After registering the MethodValidationPostProcessor we can enable method parameter validation per bean by adding the @Validated annotation. Now we can add Java Bean validation annotations to our method parameter to perform validation.

    @Service
    @Validated
    public class UserService {
    
        public User getUser(@NotBlank String uuid) {
            ...
        }
    }
    

    Here we added a @NotBlank annotation to make sure the passed uuid parameter is not null or an empty string. Whenever an invalid uuid is passed a ContraintViolationException will be thrown.

    Besides simple parameter validation we can also validate objects annotated with JSR 303 annotations.

    For example:

    public class User {
    
        @NotBlank
        private String name;
    
        // getter + setter
    }
    
    @Service
    @Validated
    public class UserService {
    
        public void createUser(@Valid User user) {
            ...
        }
    }
    

    By adding @Valid (not @Validated) we mark the user parameter for validation. The passed user object will then be validated based on the validation constraints defined in the User class. Here the name field should not be null or contain an empty string.

    How does this work?

    The MethodValidationPostProcessor bean we registered is a BeanPostProcessor that checks each bean if it is annotated with @Validated. If thats the case it will add an AOP interceptor (MethodValidationInterceptor) to intercept method calls and performs validation. The actual bean method is only called if the validation was successful.

    Because this feature relies on AOP interceptors it works only on spring beans.

    As always you can find the sources for the shown examples on GitHub.

  • Wednesday, 11 December, 2019

    Collecting application metrics with Micrometer

    What is Micrometer?

    Micrometer is a simple facade for collecting metrics inside Java applications in a vendor neutral way. You can think of SLF4J for metrics. Micrometer has built-in support for many different metrics backends, including Atlas, Datadog, Elastic, JMX and much more. In this post we will see how we can collect metrics with Micrometer in Java applications.

    Micrometer dependencies

    First we need to add the micrometer dependency to our project. Note that you need to choose the correct dependency based on the metrics backend you want to use.

    Here we choose JMX, so we need the micrometer-registry-jmx artifact.

    <dependency>
        <groupId>io.micrometer</groupId>
        <artifactId>micrometer-registry-jmx</artifactId>
        <version>1.2.0</version>
    </dependency>
    

    For example: If you want to use Elasticsearch instead of JMX, you need to add micrometer-registry-elastic.

    Creating a MeterRegistry

    Before we can start collecting metrics we need to create a MeterRegistry. The MeterRegistry is used to create Meters which then collect the actual metrics.

    MeterRegistry is an interface with different implementations, based on the metrics backend you want to use. The simplest MeterRegistry implementation is SimpleMeterRegistry that does not export the data anywhere. It simply holds the latest value of each meter in memory.

    MeterRegistry registry = new SimpleMeterRegistry();
    

    If we instead want to export metric data to JMX, we need to create a JmxMeterRegistry.

    MeterRegistry registry = new JmxMeterRegistry(new JmxConfig() {
        @Override
        public String get(String s) {
            return null;
        }
    }, Clock.SYSTEM);
    

    The get() method of the passed JmxConfig instance can be used to provide additional configuration values. We do not need this feature in our simple example, so we simply return null.

    If we want to export our metrics to multiple monitoring backends, we can use a CompositeMeterRegistry. A CompositeMeterRegistry passes the data to one or more other registries, allowing you to publish metrics to more than one metrics backend.

    For example:

    CompositeMeterRegistry registry = new CompositeMeterRegistry();
    registry.add(new JmxMeterRegistry(..));
    registry.add(new ElasticMeterRegistry(..));
    

    Meters

    Meter is the micrometer interface for collecting metrics. Example implementations of Meter are Counter, Timer and Gauge.

    Creating a Counter

    We can create a Counter using a simple builder API:

    Counter counter = Counter
            .builder("my.counter")
            .description("counts something important")
            .tag("environment", "test")
            .tag("region", "us-east")
            .register(registry);
    

    This creates a Counter named my.counter and adds it to the MeterRegistry named registry. We can also add one or more tags and an optional description to our Counter. Meters are typically created once and then used multiple times.

    To increase the counter value we can call the increment() method:

    counter.increment(); // increment by one
    counter.increment(2.5);
    

    Creating a Timer

    A Timer can be created in a similar way:

    Timer timer = Timer.builder("my.timer").register(registry);
    

    Here we skipped the optional parameters like tags or description.

    We can now add timing metrics to our timer using the record() method:

    // recording execution time of code
    timer.record(() -> {
        // do something 
    });
    
    // record a precomputed value
    timer.record(Duration.ofMillis(123));
    
    

    Viewing Results in JConsole

    Since we are using a JmxMeterRegistry our metric information can be accessed via JMX. For this we can use JConsole which can be started by executing jconsole in your <jdk>/bin directory. After connecting to your Java application process you can find the current application metrics within the MBeans tab:

    micrometer jmx metrics

    Of course you have to use a different tool to view the metrics if you use a different MetricsRegistry. For example you can use Kibana if you are using an ElasticMeterRegistry.

    Summary

    Micrometer provides an easy to use facade that can be used in Java applications for collecting application metrics. These metric information can be then exported to many different backend technologies (including Elasticsearch and JMX). You can find the source code for the examples on GitHub.

  • Monday, 28 May, 2018

    Java EE MVC: Handling form validation

    In this post we will have a look on form validation in Java EE MVC.

    Java EE MVC integrates with the Java Bean Validation API (JSR 303) which makes adding validation constraints pretty easy.

    Validation using the JAX-RS way

    Assume we have a small html form that can be used to send contact messages. To represent the form data we create a small ContactMessage bean containing the form fields and validation constraints:

    public class ContactMessage {
    
        @FormParam("message")
        @NotBlank
        @Size(max = 1000)
        private String message;
    
        // getters / setters
    }
    

    In our MVC controller we use the @BeanParam annotation to convert the form data to a ContactMessage object:

    @Controller
    @Path("/")
    public class ContactController {
    
        @POST
        public String formSubmit(@Valid @BeanParam ContactMessage message) {
            ...
        }
    }
    

    (For more details about the @BeanParam annotation, have a look at the blog post Working with bean parameters)

    By adding the @Valid annotation to the ContactMessage parameter we enable validation. If a form is submitted and the validation of the ContactMessage object fails, a ConstraintViolationException will be thrown. The controller method will not be called in this case. Instead, the exception can be handled using a generic JAX-RS ExceptionMapper like shown in another post: Global Exception handling in Java EE MVC.

    This approach is typically fine for standard JAX-RS REST endpoints. Here we often want to return a generic HTTP 400 (Bad request) status code if invalid data has been passed to the server.

    In an MVC environment we can use this behaviour to render a standard error page to the user, whenever invalid data has been passed. However, this is often not flexible enough. Often we want to return a more specific page that shows an error message to the user.

    Validation using @MvcBinding and BindingResult

    Java EE MVC provides a @MvcBinding annotation that enables an alternative exception handling mechanism. @MvcBinding can be placed on fields and method parameters together with JAX-RS binding annotations (like @FormParam):

    public class ContactMessage {
    
        @MvcBinding
        @FormParam("message")
        @NotBlank
        @Size(max = 1000)
        private String message;
    
        // getters / setters
    }
    


    This tells Java EE MVC to call the controller method instead of the generic exception handler if binding of the annotated field fails. To access binding information, we can inject a BindingResult object into our controller class:

    @Controller
    @Path("/")
    public class ContactController {
    
        @Inject
        private Models models;
    
        @Inject
        private BindingResult bindingResult;
    
        @POST
        public String formSubmit(@Valid @BeanParam ContactMessage message) {
            if (bindingResult.isFailed()) {
                models.put("bindingResult", bindingResult);
                return "/WEB-INF/jsp/contact.jsp";
            }
            return "/WEB-INF/jsp/success.jsp";
        }
    }
    

    As the name suggests, we can use the injected BindingResult object to access binding information within a controller method. In this example we simply check if there was a binding problem by calling isFailed(). By adding the bindingResult to the model, we can access it later in the view to show an error message to the user.

    A simple JSP view that displays all validation errors below the submit button looks like this:

    <form action="${mvc.contextPath}/contact" method="post">
        <label>Message:</label>
        <textarea name="message"></textarea>
        <br/>
    
        <input type="submit"/>
    
        <c:if test="${bindingResult.isFailed()}">
            <p>Form validation failed. Reasons:</p>
            <ul>
                <c:forEach items="${bindingResult.allValidationErrors}" var="validationError">
                    <li>
                        <c:out value="${validationError.paramName}: ${validationError.message}"/>
                    </li>
                </c:forEach>
            </ul>
        </c:if>
    </form>
    

    Conclusion

    Form validation is pretty easy with Java EE MVC. Validation constraints can be added to beans using JSR 303 Bean validation annotations. @MvcBinding allows us to handle validation errors within controller methods instead of using generic ExceptionMappers. BindingResult gives us access to validation information.

    As always you can find the example code on GitHub.

  • Monday, 21 May, 2018

    Using Java Stream summary statistics

    Streams of primitive types (IntStream, etc.) provide a summaryStatistics() method that can be used to get multiple statistical properties of a stream (minimum value, average value, etc.).

    Assume we have a list of people. Our goal is to get the minimum and maximum age of the people in the list using streams.

    The problem here is that the computation of the minimum and maximum values are terminal stream operations. So we need to come up with our own reduction implementation or create a new stream for every computation. A naive implementation might look like this:

    List<Person> list = Arrays.asList(
            new Person("John Blue", 28),
            new Person("Anna Brown", 53),
            new Person("Paul Black", 47)
    );
    
    int min = list.stream()
            .mapToInt(Person::getAge)
            .min()
            .orElseThrow(NoSuchElementException::new);
    
    int max = list.stream()
            .mapToInt(Person::getAge)
            .max()
            .orElseThrow(NoSuchElementException::new);
    

    Luckily Java provides a much simpler way to do this using the summaryStatistics() method:

    IntSummaryStatistics statistics = list.stream()
            .mapToInt(Person::getAge)
            .summaryStatistics();
    
    int min = statistics.getMin();
    int max = statistics.getMax();
    

    IntSummaryStatistics also provides methods to obtain the count and sum of the stream elements.

    You can find the full example code on GitHub.