Showing posts with label apache cxf. Show all posts
Showing posts with label apache cxf. Show all posts

Friday, August 30, 2024

Apache CXF at speed of ... native!

GraalVM has been around for quite a while, steadily making big waves in OpenJDK community (looking at you, JEP 483: Ahead-of-Time Class Loading & Linking). It is wonderful piece of JVM engineering that gave birth to new generation of the frameworks like Quarkus, Helidon and Micronaut, just to name a few.

But what about the old players, like Apache CXF? A large number of applications and services were built on top of it, could those benefit from GraalVM, and particularly native image compilation? The answer to this question used to vary a lot, but thanks to steady progress, GraalVM strives to make it as frictionless as possible.

In today's post, we are going to build a sample Jakarta RESTful web service using Apache CXF and Jakarta XML Binding, and compile it to native image with GraalVM Community 21.0.2+13.1.

Let us start off with the data model, which consists of a single POJO, class Customer.

import jakarta.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "Customer")
public class Customer {
    private long id;
    private String name;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

The class CustomerResource, a minimal Jakarta RESTful web service implementation, exposes a few endpoints to manage Customers, for simplicity - the state is stored in memory.

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;

@Path("/")
@Produces(MediaType.APPLICATION_XML)
public class CustomerResource {
    private final AtomicInteger id = new AtomicInteger();
    private final Map<Long, Customer> customers = new HashMap<>();

    @GET
    @Path("/customers")
    public Collection<Customer> getCustomers() {
        return customers.values();
    }

    @GET
    @Path("/customers/{id}")
    public Response getCustomer(@PathParam("id") long id) {
        final Customer customer = customers.get(id);
        if (customer != null) {
            return Response.ok(customer).build();
        } else {
            return Response.status(Status.NOT_FOUND).build();
        }
    }

    @POST
    @Path("/customers")
    public Response addCustomer(Customer customer) {
        customer.setId(id.incrementAndGet());
        customers.put(customer.getId(), customer);
        return Response.ok(customer).build();
    }

    @DELETE
    @Path("/customers/{id}")
    public Response deleteCustomer(@PathParam("id") long id) {
        if (customers.remove(id) != null) {
            return Response.noContent().build();
        } else {
            return Response.status(Status.NOT_FOUND).build();
        }
    }
}

The last piece we need is to have running web container to host the CustomerResource service. We are going to use Eclipse Jetty but any other HTTP transport supported by Apache CXF will do the job.

import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;

public class Server {
    public static org.apache.cxf.endpoint.Server create() {
        final JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
        sf.setResourceClasses(CustomerResource.class);
        sf.setResourceProvider(CustomerResource.class, new SingletonResourceProvider(new CustomerResource()));
        sf.setAddress("http://localhost:9000/");
        return sf.create();
    }
    
    public static void main(String[] args) throws Exception {
        var server = create();
        server.start();
    }
}

Literally, this is all we need from the implementation perspective. The Apache Maven dependencies list is limited to handful of those:

<dependencies>
	<dependency>
		<groupId>org.apache.cxf</groupId>
		<artifactId>cxf-rt-transports-http</artifactId>
		<version>4.0.5</version>
	</dependency>
	<dependency>
		<groupId>org.apache.cxf</groupId>
		<artifactId>cxf-rt-transports-http-jetty</artifactId>
		<version>4.0.5</version>
	</dependency>
	<dependency>
		<groupId>org.apache.cxf</groupId>
		<artifactId>cxf-rt-frontend-jaxrs</artifactId>
		<version>4.0.5</version>
	</dependency>
	<dependency>
		<groupId>ch.qos.logback</groupId>
		<artifactId>logback-classic</artifactId>
		<version>1.5.7</version>
	</dependency>
</dependencies>

Cool, so what is next? The GraalVM project provides Native Build Tools to faciliate building native images, including dedicated Apache Maven plugin. However, if we just add the plugin into the build, the resulting native image won't be functionable, even if the build succeeds:

$./target/cxf-jax-rs-graalvm-server

Exception in thread "main" java.lang.ExceptionInInitializerError
        at java.base@21.0.2/java.lang.Class.ensureInitialized(DynamicHub.java:601)
        at com.example.jaxrs.graalvm.Server.create(Server.java:27)
        at com.example.jaxrs.graalvm.Server.main(Server.java:35)
        at java.base@21.0.2/java.lang.invoke.LambdaForm$DMH/sa346b79c.invokeStaticInit(LambdaForm$DMH)
Caused by: java.util.MissingResourceException: Can't find bundle for base name org.apache.cxf.jaxrs.Messages, locale en
        at java.base@21.0.2/java.util.ResourceBundle.throwMissingResourceException(ResourceBundle.java:2059)
        at java.base@21.0.2/java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1697)
        at java.base@21.0.2/java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1600)
        at java.base@21.0.2/java.util.ResourceBundle.getBundle(ResourceBundle.java:1283)
        at org.apache.cxf.common.i18n.BundleUtils.getBundle(BundleUtils.java:94)
        at org.apache.cxf.jaxrs.AbstractJAXRSFactoryBean.<clinit>(AbstractJAXRSFactoryBean.java:69)
        ... 4 more

Why is that? GraalVM operates under closed world assumption: all classes and all bytecodes that are reachable at run time must be known at build time. Since a majority of the frameworks, Apache CXF included, does not comply with such assumptions, GraalVM needs some help: tracing agent. The way we are going to let GraalVM capture all necessary metadata is pretty straightforward:

  • add test cases which exercise the service logic (more is better)
  • run test suite using tracing agent instrumentation
  • build the native image using the metadata collected by the tracing agent

If that sounds like a plan to you, let us add the test case first:

import java.io.InputStream;
import java.io.IOException;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.Entity;
import jakarta.ws.rs.core.Response;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;

public class ServerTest {
    private org.apache.cxf.endpoint.Server server;
    
    @BeforeEach
    public void setUp() {
        server = Server.create();
        server.start();
    }
    
    @Test
    public void addNewCustomer() throws IOException {
        var client = ClientBuilder.newClient().target("http://localhost:9000/customers");
        try (InputStream in = getClass().getResourceAsStream("/add_customer.xml")) {
            try (Response response = client.request().post(Entity.xml(in))) {
                assertThat(response.getStatus(), equalTo(200));
            }
        }
    }

    @Test
    public void listCustomers() {
        var client = ClientBuilder.newClient().target("http://localhost:9000/customers");
        try (Response response = client.request().get()) {
            assertThat(response.getStatus(), equalTo(200));
        }
    }

    @AfterEach
    public void tearDown() {
        server.stop();
        server.destroy();
    }
}

Awesome, with tests in place, we could move on and integrate Native Build Tools into our Apache Maven build. It is established practice to have a dedicated profile for native image since the process could take quite a lot of time (and resources):

<profiles>
	<profile>
		<id>native-image</id>
		<activation>
			<property>
				<name>native</name>
			</property>
		</activation>
		<build>
			<plugins>
				<plugin>
					<groupId>org.graalvm.buildtools</groupId>
					<artifactId>native-maven-plugin</artifactId>
					<extensions>true</extensions>
					<version>0.10.2</version>
					<executions>
						<execution>
							<goals>
								<goal>compile-no-fork</goal>
							</goals>
							<phase>package</phase>
						</execution>
					</executions>
					<configuration>
						<agent>
							<enabled>true</enabled>
							<defaultMode>direct</defaultMode>
							<modes>
								<direct>config-output-dir=${project.build.directory}/native/agent-output</direct>
							</modes>
						</agent>
						<mainClass>com.example.jaxrs.graalvm.Server</mainClass>
						<imageName>cxf-jax-rs-graalvm-server</imageName>
						<buildArgs>
							<buildArg>--enable-url-protocols=http</buildArg>
							<buildArg>--no-fallback</buildArg>
							<buildArg>-Ob</buildArg>
						</buildArgs>
						<metadataRepository>
							<enabled>false</enabled>
						</metadataRepository>
						<resourcesConfigDirectory>${project.build.directory}/native</resourcesConfigDirectory>
					</configuration>
				</plugin>
			</plugins>
		</build>
	</profile>
</profiles>

It may look a bit complicated but fear not. The first thing to notice is that we configure tracing agent in the <agent> ... </agent> section. The captured metadata is going to be dumped into ${project.build.directory}/native/agent-output folder. Later on, the native image builder will refer to it as part of the <resourcesConfigDirectory> ... </resourcesConfigDirectory> configuration option. The profile is activated by the presence of native property.

Time to see each step in action! First thing first, run tests and capture the metadata:

$ mvn clean -Dnative test

...

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  6.977 s
[INFO] Finished at: 2024-08-30T15:50:55-04:00
[INFO] ------------------------------------------------------------------------

If we list the content of the target/native folder, we should see something like that:

$ tree target/native/

target/native/
└── agent-output
    ├── agent-extracted-predefined-classes
    ├── jni-config.json
    ├── predefined-classes-config.json
    ├── proxy-config.json
    ├── reflect-config.json
    ├── resource-config.json
    └── serialization-config.json    

If curious, you could inspect the content of each file, since it is just JSON, but we are going to proceed to the next step right away:

$ mvn -Dnative -DskipTests package

GraalVM Native Image: Generating 'cxf-jax-rs-graalvm-server' (executable)...
========================================================================================================================
Warning: Could not resolve org.junit.platform.launcher.TestIdentifier$SerializedForm for serialization configuration.
Warning: Could not resolve org.junit.platform.launcher.TestIdentifier$SerializedForm for serialization configuration.
[1/8] Initializing...                                                                                    (5.7s @ 0.10GB)
 Java version: 21.0.2+13, vendor version: GraalVM CE 21.0.2+13.1
 Graal compiler: optimization level: b, target machine: x86-64-v3
 C compiler: gcc (linux, x86_64, 9.4.0)
 Garbage collector: Serial GC (max heap size: 80% of RAM)
 2 user-specific feature(s):
 - com.oracle.svm.thirdparty.gson.GsonFeature
 - org.eclipse.angus.activation.nativeimage.AngusActivationFeature
------------------------------------------------------------------------------------------------------------------------
Build resources:
 - 9.99GB of memory (64.5% of 15.49GB system memory, determined at start)
 - 16 thread(s) (100.0% of 16 available processor(s), determined at start)
[2/8] Performing analysis...  [*****]                                                                   (31.2s @ 1.59GB)
   12,363 reachable types   (85.2% of   14,503 total)
   21,723 reachable fields  (63.2% of   34,385 total)
   61,933 reachable methods (57.6% of  107,578 total)
    3,856 types,   210 fields, and 2,436 methods registered for reflection
       62 types,    69 fields, and    55 methods registered for JNI access
        4 native libraries: dl, pthread, rt, z
[3/8] Building universe...                                                                               (4.8s @ 1.85GB)
[4/8] Parsing methods...      [**]                                                                       (3.0s @ 1.16GB)
[5/8] Inlining methods...     [***]                                                                      (2.2s @ 1.35GB)
[6/8] Compiling methods...    [*****]                                                                   (25.4s @ 1.89GB)
[7/8] Layouting methods...    [***]                                                                      (6.2s @ 1.49GB)
[8/8] Creating image...       [***]                                                                      (7.5s @ 2.03GB)
  32.41MB (49.57%) for code area:    38,638 compilation units
  30.78MB (47.08%) for image heap:  325,764 objects and 152 resources
   2.19MB ( 3.35%) for other data
  65.38MB in total

...

========================================================================================================================
Finished generating 'cxf-jax-rs-graalvm-server' in 1m 26s.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  01:30 min
[INFO] Finished at: 2024-08-30T15:58:42-04:00
[INFO] ------------------------------------------------------------------------

And we should end up with a fully functional executable, let us make sure this is the case:

$ ./target/cxf-jax-rs-graalvm-server

Aug 30, 2024 4:03:22 PM org.apache.cxf.endpoint.ServerImpl initDestination
INFO: Setting the server's publish address to be http://localhost:9000/
16:03:22.987 [main] INFO  org.eclipse.jetty.server.Server -- jetty-11.0.22; built: 2024-06-27T16:27:26.756Z; git: e711d4c7040cb1e61aa68cb248fa7280b734a3bb; jvm 21.0.2+13-jvmci-23.1-b30
16:03:22.993 [main] INFO  o.e.jetty.server.AbstractConnector -- Started ServerConnector@5725648b{HTTP/1.1, (http/1.1)}{localhost:9000}
16:03:22.994 [main] INFO  org.eclipse.jetty.server.Server -- Started Server@1f9511a6{STARTING}[11.0.22,sto=0] @24ms
16:03:22.994 [main] INFO  o.e.j.server.handler.ContextHandler -- Started o.a.c.t.h.JettyContextHandler@375bd1b5{/,null,AVAILABLE}

If we open up another terminal window and run curl from the command line, we should be hitting the instance of our service and getting successful responses back:

$curl http://localhost:9000/customers -H "Content-Type: application/xml" -d @src/test/resources/add_customer.xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Customer>
	<id>3</id>
    <name>Jack</name>
</Customer>

All the credits go to GraalVM team! Before we wrap up, you might be asking yourself if this the only way? And the short answer is "no": ideally, you should be able to add Native Build Tools and be good to go. The GraalVM Reachability Metadata Repository is the place that enables users of GraalVM native image to share and reuse metadata for libraries and frameworks in the Java ecosystem. Sadly, Apache CXF is not there just yet ... as many others.

The complete project sources are available on Github.

I πŸ‡ΊπŸ‡¦ stand πŸ‡ΊπŸ‡¦ with πŸ‡ΊπŸ‡¦ Ukraine.

Wednesday, September 30, 2020

For gourmets and practioners: pick your flavour of the reactive stack with JAX-RS and Apache CXF

When JAX-RS 2.1 specification was released back in 2017, one of its true novelties was the introduction of the reactive API extensions. The industry has acknowledged the importance of the modern programming paradigms and specification essentially mandated the first-class support of the asynchronous and reactive programming for the Client API.

But what about the server side? It was not left out, the JAX-RS 2.1 asynchronous processing model has been enriched with Java 8's CompletionStage support, certainly a step in a right direction. Any existing REST web APIs built on top of the JAX-RS 2.1 implementation (like Apache CXF for example) could benefit from such enhancements right away.

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;

@Service
@Path("/people")
public class PeopleRestService {
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public CompletionStage<List<Person>> getPeople() {
        return CompletableFuture
        	.supplyAsync(() -> Arrays.asList(new Person("a@b.com", "Tom", "Knocker")));
    }
}

Udoubtedly, CompletionStage and CompletableFuture are powerful tools but not without own quirks and limitations. The Reactive Streams specification and a number of its implementations offer a considerably better glimpse on how asynchronous and reactive programming should look like on JVM. With that, the logical question pops up: could your JAX-RS web services and APIs take advantage of the modern reactive libraries? And if the answer is positive, what does it take?

If your bets are on Apache CXF, you are certainly well positioned. The latest Apache CXF 3.2.14 / 3.3.7 / 3.4.0 release trains bring a comprehesive support of RxJava3, RxJava2 and Project Reactor. Along this post we are going to see how easy it is to plug your favorite reactive library in and place it at the forefront of your REST web APIs and services.

Since the most applications and services on the JVM are built on top of excellent Spring framework and Spring Boot, we will be developing the reference implementations using those as a foundation. The Spring Boot starter which comes along with Apache CXF distribution is taking care of most of the boring wirings you would have needed to do otherwise.

<dependency>
	<groupId>org.apache.cxf</groupId>
	<artifactId>cxf-spring-boot-starter-jaxrs</artifactId>
	<version>3.4.0</version>
</dependency>

The Project Reactor is the number one choice as the reactive foundation for Spring-based applications and services, so let us just start from that.

<dependency>
	<groupId>org.apache.cxf</groupId>
	<artifactId>cxf-rt-rs-extension-reactor</artifactId>
	<version>3.4.0</version>
</dependency>

Great, believe it or not, we are mostly done here. In order to teach Apache CXF to understand Project Reactor types like Mono or/and Flux we need to tune the configuration just a bit using ReactorCustomizer instance.

import org.apache.cxf.Bus;
import org.apache.cxf.endpoint.Server;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.apache.cxf.jaxrs.reactor.server.ReactorCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;

@Configuration
public class AppConfig {
    @Bean
    public Server rsServer(Bus bus, PeopleRestService service) {
        final JAXRSServerFactoryBean bean = new JAXRSServerFactoryBean();
        bean.getProperties(true).put("useStreamingSubscriber", true);
        bean.setBus(bus);
        bean.setAddress("/");
        bean.setServiceBean(service);
        bean.setProvider(new JacksonJsonProvider());
        new ReactorCustomizer().customize(bean);
        return bean.create();
    }
}

With such customization in-place, our JAX-RS web services and APIs could freely utilize Project Reactor primitives in a streaming fashion, for example.

import reactor.core.publisher.Flux;

@Service
@Path("/people")
public class PeopleRestService {
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Flux<Person> getPeople() {
        return Flux.just(new Person("a@b.com", "Tom", "Knocker"));
    }
}

As you probably noticed, the implementation purposely does not do anything complicated. However, once the reactive types are put at work, you could unleash the full power of the library of your choice (and Project Reactor is really good at that).

Now, when you undestand the principle, it comes the turn of the RxJava3, the last generation of the pioneering reactive library for the JVM platform.

<dependency>
	<groupId>org.apache.cxf</groupId>
	<artifactId>cxf-rt-rs-extension-rx3</artifactId>
	<version>3.4.0</version>
</dependency>

The configuration tuning is mostly identical to the one we have seen with Project Reactor, the customizer instance, ReactiveIOCustomizer, is all that changes.

import org.apache.cxf.Bus;
import org.apache.cxf.endpoint.Server;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.apache.cxf.jaxrs.rx3.server.ReactiveIOCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;

@Configuration
public class AppConfig {
    @Bean
    public Server rsServer(Bus bus, PeopleRestService service) {
        final JAXRSServerFactoryBean bean = new JAXRSServerFactoryBean();
        bean.getProperties(true).put("useStreamingSubscriber", true);
        bean.setBus(bus);
        bean.setAddress("/");
        bean.setServiceBean(service);
        bean.setProvider(new JacksonJsonProvider());
        new ReactiveIOCustomizer().customize(bean);
        return bean.create();
    }
}

The list of supported types includes Flowable, Single and Observable, the equivalent implementation in terms of RxJava3 primitives may look like this.


import io.reactivex.rxjava3.core.Flowable;

@Service
@Path("/people")
public class PeopleRestService {
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Flowable<Person> getPeople() {
        return Flowable.just(new Person("a@b.com", "Tom", "Knocker"));
    }
}

Pretty simple, isn't it? If you stuck with an older generation, RxJava2, nothing to worry about, Apache CXF has you covered.

<dependency>
	<groupId>org.apache.cxf</groupId>
	<artifactId>cxf-rt-rs-extension-rx2</artifactId>
	<version>3.4.0</version>
</dependency>

The same configuration trick with applying the customizer (which may look annoying at this point to be fair) is all that is required.

import org.apache.cxf.Bus;
import org.apache.cxf.endpoint.Server;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.apache.cxf.jaxrs.rx2.server.ReactiveIOCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;

@Configuration
public class AppConfig {
    @Bean
    public Server rsServer(Bus bus, PeopleRestService service) {
        final JAXRSServerFactoryBean bean = new JAXRSServerFactoryBean();
        bean.getProperties(true).put("useStreamingSubscriber", true);
        bean.setBus(bus);
        bean.setAddress("/");
        bean.setServiceBean(service);
        bean.setProvider(new JacksonJsonProvider());
        new ReactiveIOCustomizer().customize(bean);
        return bean.create();
    }
}

And we are good to go, ready to use the familiar reactive types Observable, Flowable and Single.

import io.reactivex.Flowable;
import io.reactivex.Observable;

@Service
@Path("/people")
public class PeopleRestService {
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Observable<Person> getPeople() {
        return Flowable
            .just(new Person("a@b.com", "Tom", "Knocker"))
            .toObservable();
    }
}

Last but not least, if you happens to be using the first generation of RxJava, it is also available with Apache CXF but certainly not recommended for production (as it has EOLed a couple of years ago).

Reactive programming paradigm is steadily getting more and more traction. It is great to see that the ecosystem embraces that and frameworks like Apache CXF are not an exception. If you are looking for robust foundation to build reactive and/or asynchronous REST web APIs on JVM, Apache CXF is worth considering, please give it a try!

The complete source code is available on Github.

Saturday, May 11, 2019

When HTTP status code is not enough: tackling web APIs error reporting

One area of the RESTful web APIs design, quite frequently overlooked, is how to report errors and problems, either related to business or application. The proper usage of the HTTP status codes comes to mind first, and although quite handy, often it is not informative enough. Let us take 400 Bad Request for example. Yes, it clearly states that the request is problematic, but what exactly is wrong?

The RESTful architectural style does not dictate what should be done in this case and so everyone is inventing its own styles, conventions and specifications. It could be as simple as including error message into the response or as shortsighted as copy/pasting long stack traces (in case of Java or .NET, to name a few cultprits). There is no shortage of ideas but luckily, we have at least some guidance available in the form of RFC 7807: Problem Details for HTTP APIs. Despite the fact that it is not an official specification but a draft (still), it outlines the good common principles on the problem at hand and this is what we are going to talk about in this post.

In the nutshell, RFC 7807: Problem Details for HTTP APIs just proposes the error or problem representation (in JSON or XML formats) which may include at least the following details:

  • type - A URI reference that identifies the problem type
  • title - A short, human-readable summary of the problem type
  • status - The HTTP status code
  • detail - A human-readable explanation specific to this occurrence of the problem
  • instance - A URI reference that identifies the specific occurrence of the problem
More importantly, the problem type definitions may extend the problem details object with additional members, contributing to the ones above. As you see, it looks dead simple from the implementation perspective. Even better, thanks to Zalando, we already have the RFC 7807: Problem Details for HTTP APIs implementation for Java (and Spring Web in particular). So ... let us give it a try!

Our imaginary People Management web API is going to be built using the state of the art technology stack, Spring Boot and Apache CXF, the popular web services framework and JAX-RS 2.1 implementation. To keep it somewhat simple, there are only two endpoints which are exposed: registration and lookup by person identifier.

Sweeping aside the tons of issues and business constraints you may run into while developing the real-world services, even with this simple API a few things may go wrong. The first problem we age going to tackle is what if the person you are looking for is not registered yet? Looks like a fit for 404 Not Found, right? Indeed, let us start with our first problem, PersonNotFoundProblem!

public class PersonNotFoundProblem extends AbstractThrowableProblem {
    private static final long serialVersionUID = 7662154827584418806L;
    private static final URI TYPE = URI.create("http://localhost:21020/problems/person-not-found");
    
    public PersonNotFoundProblem(final String id, final URI instance) {
        super(TYPE, "Person is not found", Status.NOT_FOUND, 
            "Person with identifier '" + id + "' is not found", instance, 
                null, Map.of("id", id));
    }
}

It resembles a lot the typical Java exception, and it really is one, since AbstractThrowableProblem is the subclass of the RuntimeException. As such, we could throw it from our JAX-RS API.

@Produces({ MediaType.APPLICATION_JSON, "application/problem+json" })
@GET
@Path("{id}")
public Person findById(@PathParam("id") String id) {
    return service
        .findById(id)
        .orElseThrow(() -> new PersonNotFoundProblem(id, uriInfo.getRequestUri()));
}

If we run the server and just try to fetch the person providing any identifier, the problem detail response is going to be returned back (since the dataset is not pre-populated), for example:

$ curl "http://localhost:21020/api/people/1" -H  "Accept: */*" 

HTTP/1.1 404
Content-Type: application/problem+json

{
    "type" : "http://localhost:21020/problems/person-not-found",
    "title" : "Person is not found",
    "status" : 404,
    "detail" : "Person with identifier '1' is not found",
    "instance" : "http://localhost:21020/api/people/1",
    "id" : "1"
}

Please notice the usage of the application/problem+json media type along with additional property id being included into the response. Although there are many things which could be improved, it is arguably better than just naked 404 (or 500 caused by EntityNotFoundException). Plus, the documentation section behind this type of the problem (in our case, http://localhost:21020/problems/person-not-found) could be consulted in case further clarifications may be needed.

So designing the problems after exceptions is just one option. You may often (and for very valid reasons) restrain from coupling you business logic with unrelated details. In this case, it is perfectly valid to return the problem details as the response payload from the JAX-RS resource. As an example, the registration process may raise NonUniqueEmailException so our web API layer could transform it into appropriate problem detail.

@Consumes(MediaType.APPLICATION_JSON)
@Produces({ MediaType.APPLICATION_JSON, "application/problem+json" })
@POST
public Response register(@Valid final CreatePerson payload) {
    try {
        final Person person = service.register(payload.getEmail(), 
            payload.getFirstName(), payload.getLastName());
            
        return Response
            .created(uriInfo.getRequestUriBuilder().path(person.getId()).build())
            .entity(person)
            .build();

    } catch (final NonUniqueEmailException ex) {
        return Response
            .status(Response.Status.BAD_REQUEST)
            .type("application/problem+json")
            .entity(Problem
                .builder()
                .withType(URI.create("http://localhost:21020/problems/non-unique-email"))
                .withInstance(uriInfo.getRequestUri())
                .withStatus(Status.BAD_REQUEST)
                .withTitle("The email address is not unique")
                .withDetail(ex.getMessage())
                .with("email", payload.getEmail())
                .build())
            .build();
        }
    }

To trigger this issue, it is enough to run the server instance and try to register the same person twice, like we have done below.

$ curl -X POST "http://localhost:21020/api/people" \ 
     -H  "Accept: */*" -H "Content-Type: application/json" \
     -d '{"email":"john@smith.com", "firstName":"John", "lastName": "Smith"}'

HTTP/1.1 400                                                                              
Content-Type: application/problem+json                                                           
                                                                                                                                                                                   
{                                                                                         
    "type" : "http://localhost:21020/problems/non-unique-email",                            
    "title" : "The email address is not unique",                                            
    "status" : 400,                                                                         
    "detail" : "The email 'john@smith.com' is not unique and is already registered",        
    "instance" : "http://localhost:21020/api/people",                                       
    "email" : "john@smith.com"                                                              
}                                                                                         

Great, so our last example is a bit more complicated but, probably, at the same time, the most realistic one. Our web API heavily relies on Bean Validation in order to make sure the input provided by the consumers of the API is valid. How would we represent the validation errors as the problem details? The most straightforward way is to supply the dedicated ExceptionMapper provider, which is the part of the JAX-RS specification. Let us introduce one.

@Provider
public class ValidationExceptionMapper implements ExceptionMapper<ValidationException> {
    @Context private UriInfo uriInfo;
    
    @Override
    public Response toResponse(final ValidationException ex) {
        if (ex instanceof ConstraintViolationException) {
            final ConstraintViolationException constraint = (ConstraintViolationException) ex;
            
            final ThrowableProblem problem = Problem
                    .builder()
                    .withType(URI.create("http://localhost:21020/problems/invalid-parameters"))
                    .withTitle("One or more request parameters are not valid")
                    .withStatus(Status.BAD_REQUEST)
                    .withInstance(uriInfo.getRequestUri())
                    .with("invalid-parameters", constraint
                        .getConstraintViolations()
                        .stream()
                        .map(this::buildViolation)
                        .collect(Collectors.toList()))
                    .build();

            return Response
                .status(Response.Status.BAD_REQUEST)
                .type("application/problem+json")
                .entity(problem)
                .build();
        }
        
        return Response
            .status(Response.Status.INTERNAL_SERVER_ERROR)
            .type("application/problem+json")
            .entity(Problem
                .builder()
                .withTitle("The server is not able to process the request")
                .withType(URI.create("http://localhost:21020/problems/server-error"))
                .withInstance(uriInfo.getRequestUri())
                .withStatus(Status.INTERNAL_SERVER_ERROR)
                .withDetail(ex.getMessage())
                .build())
            .build();
    }

    protected Map<?, ?> buildViolation(ConstraintViolation<?> violation) {
        return Map.of(
                "bean", violation.getRootBeanClass().getName(),
                "property", violation.getPropertyPath().toString(),
                "reason", violation.getMessage(),
                "value", Objects.requireNonNullElse(violation.getInvalidValue(), "null")
            );
    }
}

The snippet above distingushes two kind of issues: the ConstraintViolationExceptions indicate the invalid input and are mapped to 400 Bad Request, whereas generic ValidationExceptions indicate the problem on the server side and are mapped to 500 Internal Server Error. We only extract the basic details about violations, however even that improves the error reporting a lot.

$ curl -X POST "http://localhost:21020/api/people" \
    -H  "Accept: */*" -H "Content-Type: application/json" \
    -d '{"email":"john.smith", "firstName":"John"}' -i    

HTTP/1.1 400                                                                    
Content-Type: application/problem+json                                              
                                                                                
{                                                                               
    "type" : "http://localhost:21020/problems/invalid-parameters",                
    "title" : "One or more request parameters are not valid",                     
    "status" : 400,                                                               
    "instance" : "http://localhost:21020/api/people",                             
    "invalid-parameters" : [ 
        {
            "reason" : "must not be blank",                                             
            "value" : "null",                                                           
            "bean" : "com.example.problem.resource.PeopleResource",                     
            "property" : "register.payload.lastName"                                    
        }, 
        {                                                                          
            "reason" : "must be a well-formed email address",                           
            "value" : "john.smith",                                                     
            "bean" : "com.example.problem.resource.PeopleResource",                     
            "property" : "register.payload.email"                                       
        } 
    ]                                                                           
}                                                                               

This time the additional information bundled into the invalid-parameters member is quite verbose: we know the class (PeopleResource), method (register), the method's argument (payload) and the properties (lastName and email) respectively (all that extracted from the property path).

Meaningful error reporting is one of corner stones of the modern RESTful web APIs. Often it is not easy but definitely worth the efforts. The consumers (which often are just other developers) should have a clear understanding of what went wrong and what to do about it. The RFC 7807: Problem Details for HTTP APIs is a step into right direction and libraries like problem and problem-spring-web are here to back you up, please make use of them.

The complete source code is available on Github.

Monday, April 30, 2018

Moving With The Times: Towards OpenAPI v3.0.0 adoption in JAX-RS APIs

It is terrifying to see how fast time passes! The OpenAPI specification 3.0.0, a major revamp of so-get-used-to Swagger specification, has been released mostly one year ago but it took awhile for tooling to catch up. However, with the recent official release of the Swagger Core 2.0.0 things are going to accelerate for sure.

To prove the point, Apache CXF, the well-known JAX-RS 2.1 implementation, is one of the first adopters of the OpenAPI 3.0.0 and in today's post we are going to take a look how easy your JAX-RS 2.1 APIs could benefit from it.

As always, to keep things simple we are going to design a people management web APIs with just a handful set of resources to support it, nothing too exciting here.

POST   /api/people
GET    /api/people/{email}
GET    /api/people
DELETE /api/people/{email}

Our model would consist of a single Person class.

public class Person {
    private String email;
    private String firstName;
    private String lastName;
}

To add a bit of magic, we would be using Spring Boot to get us up and running as fast as possible. With that, let us start to fill in the dependencies (assuming we are using Apache Maven for build management).

<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-spring-boot-starter-jaxrs</artifactId>
    <version>3.2.4</version>
</dependency>

In the recent 3.2.x releases Apache CXF introduces a new module cxf-rt-rs-service-description-openapi-v3 dedicated to OpenAPI 3.0.0, based on Swagger Core 2.0.0.

<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-rs-service-description-openapi-v3</artifactId>
    <version>3.2.4</version>
</dependency>

<dependency>
    <groupId>org.webjars</groupId>
    <artifactId>swagger-ui</artifactId>
    <version>3.13.6</version>
</dependency>

The presence of the Swagger UI is not strictly necessary, but this is exceptionally useful and beautiful tool to explore your APIs (and if it is available on classpath, Apache CXF seamlessly integrates it into your applications as we are going to see in a bit).

The prerequisites are in place, let us do some coding! Before we begin, it is worth to note that the Swagger Core 2.0.0 has many ways to populate the OpenAPI 3.0.0 definitions for your services, including property files, annotations or programmatically. Along this post we are going to use annotations only.

@OpenAPIDefinition(
    info = @Info(
        title = "People Management API",
        version = "0.0.1-SNAPSHOT",
        license = @License(
            name = "Apache 2.0 License",
            url = "http://www.apache.org/licenses/LICENSE-2.0.html"
        )
    )
)
@ApplicationPath("api")
public class JaxRsApiApplication extends Application {
}

Looks pretty simple, the @OpenAPIDefinition sets the top-level definition for all our web APIs. Moving on to the PeopleRestService, we just add the @Tag annotation to, well, tag our API.

@Path( "/people" ) 
@Tag(name = "people")
public class PeopleRestService {
    // ...
}

Awesome, nothing complicated so far. The meaty part starts with web API operation definitions, so let us take a look on the first example, the operation to fetch everyone.

@Produces(MediaType.APPLICATION_JSON)
@GET
@Operation(
    description = "List all people", 
    responses = {
        @ApiResponse(
            content = @Content(
                array = @ArraySchema(schema = @Schema(implementation = Person.class))
            ),
            responseCode = "200"
        )
    }
)
public Collection<Person> getPeople() {
    // ...
}

Quite a few annotations but by and large, looks pretty clean and straightforward. Let us take a look on another one, the endpoint to find the person by its e-mail address.

@Produces(MediaType.APPLICATION_JSON)
@Path("/{email}")
@GET
@Operation(
    description = "Find person by e-mail", 
    responses = {
        @ApiResponse(
            content = @Content(schema = @Schema(implementation = Person.class)), 
            responseCode = "200"
        ),
        @ApiResponse(
            responseCode = "404", 
            description = "Person with such e-mail doesn't exists"
        )
    }
)
public Person findPerson(
        @Parameter(description = "E-Mail address to lookup for", required = true) 
        @PathParam("email") final String email) {
    // ...
}

In the same vein, the operation to remove the person by e-mail looks mostly identical.

@Path("/{email}")
@DELETE
@Operation(
    description = "Delete existing person",
    responses = {
        @ApiResponse(
            responseCode = "204",
            description = "Person has been deleted"
        ),
        @ApiResponse(
            responseCode = "404", 
            description = "Person with such e-mail doesn't exists"
        )
     }
)
public Response deletePerson(
        @Parameter(description = "E-Mail address to lookup for", required = true ) 
        @PathParam("email") final String email) {
    // ...
}

Great, let us wrap up by looking into last, arguably the most interesting endpoint which adds a new person (the choice to use the @FormParam is purely to illustrate the different flavor of the APIs).

@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.APPLICATION_JSON)
@POST
@Operation(
    description = "Create new person",
    responses = {
        @ApiResponse(
            content = @Content(
                schema = @Schema(implementation = Person.class), 
                mediaType = MediaType.APPLICATION_JSON
            ),
            headers = @Header(name = "Location"),
            responseCode = "201"
        ),
        @ApiResponse(
            responseCode = "409", 
            description = "Person with such e-mail already exists"
        )
    }
)
public Response addPerson(@Context final UriInfo uriInfo,
        @Parameter(description = "E-Mail", required = true) 
        @FormParam("email") final String email, 
        @Parameter(description = "First Name", required = true) 
        @FormParam("firstName") final String firstName, 
        @Parameter(description = "Last Name", required = true) 
        @FormParam("lastName") final String lastName) {
    // ...
}

If you have an experience with documenting web APIs using older Swagger specifications, you might find the approach quite familiar but more verbose (or better to say, formalized). It is the result of the tremendous work which specification leads and community has done to make it as complete and extensible as possible.

The APIs are defined and documented, it is time to try them out! The missing piece though is the Spring configuration where we would initialize and expose our JAX-RS web services.

@Configuration
@EnableAutoConfiguration
@ComponentScan(basePackageClasses = PeopleRestService.class)
public class AppConfig {
    @Autowired private PeopleRestService peopleRestService;
 
    @Bean(destroyMethod = "destroy")
    public Server jaxRsServer(Bus bus) {
        final JAXRSServerFactoryBean factory = new JAXRSServerFactoryBean();

        factory.setApplication(new JaxRsApiApplication());
        factory.setServiceBean(peopleRestService);
        factory.setProvider(new JacksonJsonProvider());
        factory.setFeatures(Arrays.asList(new OpenApiFeature()));
        factory.setBus(bus);
        factory.setAddress("/");

        return factory.create();
    }

    @Bean
    public ServletRegistrationBean cxfServlet() {
        final ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new CXFServlet(), "/api/*");
        servletRegistrationBean.setLoadOnStartup(1);
        return servletRegistrationBean;
    }
}

The OpenApiFeature is a key ingredient here which takes care of all the integration and introspection. The Spring Boot application is the last touch to finish the picture.

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(AppConfig.class, args);
    }
}

Let us build and run it right away:

mvn clean package 
java -jar target/jax-rs-2.1-openapi-0.0.1-SNAPSHOT.jar

Having the application started, the OpenAPI 3.0.0 specification of our web APIs should be live and available for consumption in the JSON format at:

http://localhost:8080/api/openapi.json

Or in YAML format at:

http://localhost:8080/api/openapi.json

Wouldn't it be great to explore our web APIs and play with it? Since we included Swagger UI dependency, this is no brainer, just navigate to http://localhost:8080/api/api-docs?url=/api/openapi.json:

A special attention to be made to the small icon Swagger UI places alongside your API version, hinting about its conformity to OpenAPI 3.0.0 specification.

Just to note here, there is nothing special in using Spring Boot. In case you are using Apache CXF inside the OSGi container (like Apache Karaf for example), the integration with OpenAPI 3.0.0 is also available (please check out the official documentation and samples if you are interested in the subject).

It all looks easy and simple, but what about migrating to OpenAPI 3.0.0 from older versions of the Swagger specifications? The Apache CXF has an powerful feature to convert older the specifications on the fly but in general the OpenApi.Tools portal is a right place to evaluate your options.

Should you migrate to OpenAPI 3.0.0? I honestly believe you should, at least should try experimenting with it, but please be aware that the tooling is still not mature enough, expect a few roadblocks along the way (which you would be able to overcome by contributing the patches, by the way). But undoubtedly, the future is bright!

The complete project sources are available on Github.

Sunday, November 27, 2016

Keep your promises: contract-based testing for JAX-RS APIs

It's been a while since we talked about testing and applying effective TDD practices, particularly related to REST(ful) web services and APIs. But this topic should have never been forgotten, especially in the world where everyone is doing microservices, whatever it means, implies or takes.

To be fair, there are quite a lot of areas where microservice-based architecture shines and allows organizations to move and innovate much faster. But without a proper discipline, it also makes our systems fragile, as they become very loosely coupled. In today's post we are going to talk about contract-based testing and consumer-driven contracts as a practical and reliable techniques to ensure that our microservices fulfill their promises.

So, how does contract-based testing work? In nutshell, it is surprisingly simple technique and is guided by following steps:

  • provider (let say Service A) publishes its contact (or specification), the implementation may not even be available at this stage
  • consumer (let say Service B) follows this contract (or specification) to implement conversations with Service A
  • additionally, consumer introduces a test suite to verify its expectations regarding Service A contract fulfillment
In case of SOAP web services and APIs, things are obvious as there is an explicit contract in a form of WSDL file. But in case of REST(ful) APIs, there are a lot of different options around the corner (WADL, RAML, Swagger, ...) and still no agreement on the one. It may sound complicated but please don't get upset, because Pact is coming on the rescue!

Pact is family of frameworks for supporting consumer-driven contracts testing. There are many language bindings and implementations available, including JVM ones, JVM Pact and Scala-Pact. To evolve such a polyglot ecosystem, Pact also includes a dedicated specification so to provide interoperability between different implementations.

Great, Pact is there, the stage is set and we are ready to take off with some real code snippets. Let us assume we are developing a REST(ful) web API for managing people, using terrific Apache CXF and JAX-RS 2.0 specification. To keep things simple, we are going to introduce only two endpoints:

  • POST /people/v1 to create new person
  • GET /people/v1?email=<email> to find person by email address
Essentially, we may not bother and just communicate these minimal pieces of our service contract to everyone so let the consumers deal with that themselves (and indeed, Pact supports such a scenario). But surely, we are not like that, we do care and would like to document our APIs comprehensively, likely we are already familiar with Swagger. With that, here is our PeopleRestService.
@Api(value = "Manage people")
@Path("/people/v1")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class PeopleRestService {
    @GET
    @ApiOperation(value = "Find person by e-mail", 
        notes = "Find person by e-mail", response = Person.class)
    @ApiResponses({
        @ApiResponse(code = 404, 
            message = "Person with such e-mail doesn't exists", 
            response = GenericError.class)
    })
    public Response findPerson(
        @ApiParam(value = "E-Mail address to lookup for", required = true) 
        @QueryParam("email") final String email) {
        // implementation here
    }

    @POST
    @ApiOperation(value = "Create new person", 
        notes = "Create new person", response = Person.class)
    @ApiResponses({
        @ApiResponse(code = 201, 
            message = "Person created successfully", 
            response = Person.class),
        @ApiResponse(code = 409, 
            message = "Person with such e-mail already exists", 
            response = GenericError.class)
    })
    public Response addPerson(@Context UriInfo uriInfo, 
        @ApiParam(required = true) PersonUpdate person) {
        // implementation here
    }
}

The implementation details are not important at the moment, however let us take a look at the GenericError, PersonUpdate and Person classes as they are an integral part of our service contract.

@ApiModel(description = "Generic error representation")
public class GenericError {
    @ApiModelProperty(value = "Error message", required = true)
    private String message;
}

@ApiModel(description = "Person resource representation")
public class PersonUpdate {
    @ApiModelProperty(value = "Person's first name", required = true) 
    private String email;
    @ApiModelProperty(value = "Person's e-mail address", required = true) 
    private String firstName;
    @ApiModelProperty(value = "Person's last name", required = true) 
    private String lastName;
    @ApiModelProperty(value = "Person's age", required = true) 
    private int age;
}

@ApiModel(description = "Person resource representation")
public class Person extends PersonUpdate {
    @ApiModelProperty(value = "Person's identifier", required = true) 
    private String id;
}

Excellent! Once we have Swagger annotations in place and Apache CXF Swagger integration turned on, we could generate swagger.json specification file, bring it to live in Swagger UI and distribute to every partner or interested consumer.

Would be great if we could use this Swagger specification along with Pact framework implementation to serve as a service contract. Thanks to Atlassian, we are certainly able to do that using swagger-request-validator, a library for validating HTTP request/respons against a Swagger/OpenAPI specification which nicely integrates with Pact JVM as well.

Cool, now let us switch sides from provider to consumer and try to figure out what we can do having such Swagger specification in our hands. It turns out, we can do a lot of things. For example, let us take a look at the POST action, which creates new person. As a client (or consumer), we could express our expectations in such a form that having a valid payload submitted along with the request, we expect HTTP status code 201 to be returned by the provider and the response payload should contain a new person with identifier assigned. In fact, translating this statement into Pact JVM assertions is pretty straightforward.

@Pact(provider = PROVIDER_ID, consumer = CONSUMER_ID)
public PactFragment addPerson(PactDslWithProvider builder) {
    return builder
        .uponReceiving("POST new person")
        .method("POST")
        .path("/services/people/v1")
        .body(
            new PactDslJsonBody()
                .stringType("email")
                .stringType("firstName")
                .stringType("lastName")
                .numberType("age")
        )
        .willRespondWith()
        .status(201)
        .matchHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
        .body(
            new PactDslJsonBody()
                .uuid("id")
                .stringType("email")
                .stringType("firstName")
                .stringType("lastName")
                .numberType("age")
        )
       .toFragment();
}

To trigger the contract verification process, we are going to use awesome JUnit and very popular REST Assured framework. But before that, let us clarify on what is PROVIDER_ID and CONSUMER_ID from the code snippet above. As you may expect, PROVIDER_ID is the reference to the contract specification. For simplicity, we would fetch Swagger specification from running PeopleRestService endpoint, luckily Spring Boot testing improvements make this task a no-brainer.

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, 
    classes = PeopleRestConfiguration.class)
public class PeopleRestContractTest {
    private static final String PROVIDER_ID = "People Rest Service";
    private static final String CONSUMER_ID = "People Rest Service Consumer";

    private ValidatedPactProviderRule provider;
    @Value("${local.server.port}")
    private int port;

    @Rule
    public ValidatedPactProviderRule getValidatedPactProviderRule() {
        if (provider == null) {
            provider = new ValidatedPactProviderRule("http://localhost:" + port + 
                "/services/swagger.json", null, PROVIDER_ID, this);
        }

        return provider;
    }
}

The CONSUMER_ID is just a way to identify the consumer, not much to say about it. With that, we are ready to finish up with our first test case:

@Test
@PactVerification(value = PROVIDER_ID, fragment = "addPerson")
public void testAddPerson() {
    given()
        .contentType(ContentType.JSON)
        .body(new PersonUpdate("tom@smith.com", "Tom", "Smith", 60))
        .post(provider.getConfig().url() + "/services/people/v1");
}

Awesome! As simple as that, just please notice the presence of @PactVerification annotation where we are referencing the appropriate verification fragment by name, in this case it points out to addPerson method we have introduced before.

Great, but ... what the point? Glad you are asking, because from now on any change in the contract which may not be backward compatible will break our test case. For example, if provider decides to remove the id property from the response payload, the test case will fail. Renaming the request payload properties, big no-no, again, test case will fail. Adding new path parameters? No luck, test case won't let it pass. You may go even further than that and fail on every contract change, even if it backward-compatible (using swagger-validator.properties for fine-tuning).

validation.response=ERROR
validation.response.body.missing=ERROR

No a very good idea but still, if you need it, it is there. Similarly, let us add a couple of more test cases for GET endpoint, starting from successful scenario, where person we are looking for exists, for example:

@Pact(provider = PROVIDER_ID, consumer = CONSUMER_ID)
public PactFragment findPerson(PactDslWithProvider builder) {
    return builder
        .uponReceiving("GET find person")
        .method("GET")
        .path("/services/people/v1")
        .query("email=tom@smith.com")
        .willRespondWith()
        .status(200)
        .matchHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
        .body(
            new PactDslJsonBody()
                .uuid("id")
                .stringType("email")
                .stringType("firstName")
                .stringType("lastName")
                .numberType("age")
        )
        .toFragment();
}

@Test
@PactVerification(value = PROVIDER_ID, fragment = "findPerson")
public void testFindPerson() {
    given()
        .contentType(ContentType.JSON)
        .queryParam("email", "tom@smith.com")
        .get(provider.getConfig().url() + "/services/people/v1");
}

Please take a note that here we introduced query string verification using query("email=tom@smith.com") assertion. Following the possible outcomes, let us also cover the unsuccessful scenario, where person does not exist and we expect some error to be returned, along with 404 status code, for example:

@Pact(provider = PROVIDER_ID, consumer = CONSUMER_ID)
public PactFragment findNonExistingPerson(PactDslWithProvider builder) {
    return builder
        .uponReceiving("GET find non-existing person")
        .method("GET")
        .path("/services/people/v1")
        .query("email=tom@smith.com")
        .willRespondWith()
        .status(404)
        .matchHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
        .body(new PactDslJsonBody().stringType("message"))
        .toFragment();
}

@Test
@PactVerification(value = PROVIDER_ID, fragment = "findNonExistingPerson")
public void testFindPersonWhichDoesNotExist() {
    given()
        .contentType(ContentType.JSON)
        .queryParam("email", "tom@smith.com")
        .get(provider.getConfig().url() + "/services/people/v1");
}

Really brilliant, maintainable, understandable and non-intrusive approach to address such a complex and important problems as contract-based testing and consumer-driven contracts. Hopefully, this somewhat new testing technique would help you to catch more issues during the development phase, way before they would have a chance to leak into production.

Thanks to Swagger we were able to take a few shortcuts, but in case you don't have such a luxury, Pact has quite rich specification which you are very welcome to learn and use. In any case, Pact JVM does a really great job in helping you out writing small and concise test cases.

The complete project sources are available on Github.

Monday, September 19, 2016

Stop being clueless, just instrument and measure: using metrics to gain insights about your JAX-RS APIs

How often we, developers, build these shiny REST(ful) APIs (or microservices, joining the hype here) hoping they are going to just work in production? There is enormous amount of frameworks and toolkits out there which give us the ability to be very productive at development, however when things are deployed in production, most of them keep us clueless about what it is going on.

Spring Boot is certainly an exception from this rule and in today's post we are going to talk about using Spring Boot Actuator along with terrific Dropwizard Metrics library to collect and expose metrics about Apache CXF-based JAX-RS APIs. To keep things even more interesting, we are going to feed the metrics into amazing Prometheus collector and visualize using beautiful Grafana dashboards.

With that, let us get started by defining simple JAX-RS service to manage people, PeopleRestService. We are not going to plug it to any external storage or whatnot but instead just cheat a bit by relying on Spring Reactor project and introducing random delays while returning a predefined response.

@Path("/people")
@Component
public class PeopleRestService {
    private final Random random = new Random();
 
    @GET
    @Produces({MediaType.APPLICATION_JSON})
    public Collection<Person> getPeople() {
        return Flux
            .just(
                new Person("a@b.com", "John", "Smith"), 
                new Person("c@b.com", "Bob", "Bobinec")
            )
            .delayMillis(random.nextInt(1000))
            .toStream()
            .collect(Collectors.toList());
    }
}

Because we are going to use Spring Boot and its automagic discovery capabilities, the configuration is going look rather trivial. We have already talked about using Spring Boot along with Apache CXF but now even this part has been improved, thanks to the Apache CXF Spring Boot Starter available (it becomes just a matter of adding one more dependency to your project).

@Configuration
@EnableAutoConfiguration
public class AppConfig {
    @Bean(destroyMethod = "destroy")
    public Server jaxRsServer(final Bus bus) {
        final JAXRSServerFactoryBean factory = new JAXRSServerFactoryBean();

        factory.setServiceBean(peopleRestService());
        factory.setProvider(new JacksonJsonProvider());
        factory.setBus(bus);
        factory.setAddress("/");

        return factory.create();
    }
 
    @Bean
    public PeopleRestService peopleRestService() {
        return new PeopleRestService();
    }
}

At this point we did everything we needed to have a bare bones Spring Boot hosting Apache CXF-based JAX-RS service. Please take a note that by default with Apache CXF Spring Boot Starter all APIs are served under /services/* mapping.

Till now we said nothing about metrics yet and that is what we are going to talk about next. Dropwizard Metrics is a de-facto standard for JVM applications and has a rich set of different kind of metrics (meters, gauges, counters, histograms, ...) and reporters (console, JMX, HTTP, ...). Consequently, the MetricRegistry is a central place to manage all the metrics. And surely, the typical way to expose metrics for JVM-based application is JMX so let us include the respective beans into configuration.

@Bean(initMethod = "start", destroyMethod = "stop")
public JmxReporter jmxReporter() {
    return JmxReporter.forRegistry(metricRegistry()).build();
}
 
@Bean
public MetricRegistry metricRegistry() {
    return new MetricRegistry();
}

You are free to create as many metrics as you need and we could have added a few for our PeopleRestService as well. But luckily, Apache CXF has a dedicated MetricsFeature feature to integrate with Dropwizard Metrics and collect all the relevant ones, with zero effort. A minor update of the JAXRSServerFactoryBean initialization is enough.

@Bean(destroyMethod = "destroy")
public Server jaxRsServer(final Bus bus) {
    final JAXRSServerFactoryBean factory = new JAXRSServerFactoryBean();

    factory.setServiceBean(peopleRestService());
    factory.setProvider(new JacksonJsonProvider());
    factory.setBus(bus);
    factory.setAddress("/");
    factory.setFeatures(Collections.singletonList(
        new MetricsFeature(new CodahaleMetricsProvider(bus))
    ));
    factory.setProperties(
        Collections.singletonMap(
            "org.apache.cxf.management.service.counter.name", 
            "cxf-services."
        )
    );

    return factory.create();
}

Just a quick note about org.apache.cxf.management.service.counter.name. By default, Apache CXF is going to name metrics quite verbosely, including unique bus identifier as part of the name as well. It is not very readable so we just override the default behaviour using static 'cxf-services.' prefix. This is how those metrics are going to look like in the JMX console.

It looks terrific, but JMX is not a very pleasant piece of technology to dial with, could we do better? Here is where Spring Boot Actuator comes into play. Along with many other endpoints, it is able to expose all the metrics over HTTP protocol by adding a couple of properties to application.yml file:

endpoints:
  jmx:
    enabled: true
    unique-names: true

management:
  security:
    enabled: true 

It is important to mention here that metrics, along with other Spring Boot Actuator endpoints, may expose a sensitive details about your application so it is always a good idea to protect them, for example, using Spring Security and HTTP Basic Authentication. Again, a few configuration properties in application.yml will do all the work:

security:
  ignored:
    - /services/**
  user:
    name: guest
    password: guest

Brilliant, if we run our application and access /metrics endpoint (providing guest/guest as credentials), we should see quite an extensive list of metrics, like these ones:

> curl -u guest:guest http://localhost:19090/metrics

{
    "classes": 8673,
    "classes.loaded": 8673,
    "classes.unloaded": 0,
    "counter.status.200.metrics": 5,
    "counter.status.200.services.people": 1,
    "counter.status.401.error": 2,
    "cxf-services.Attribute=Checked Application Faults.count": 0,
    "cxf-services.Attribute=Checked Application Faults.fifteenMinuteRate": 0.0,
    "cxf-services.Attribute=Checked Application Faults.fiveMinuteRate": 0.0,
    "cxf-services.Attribute=Checked Application Faults.meanRate": 0.0,
    ...
}

It would be great to have some dedicated monitoring solution which could understand these metrics, store them somewhere and give us useful insights and aggregations in real-time. Prometheus is exactly the tool we are looking for but there are bad and good news. On a not so good side, Prometheus does not understand the format which Spring Boot Actuator uses to expose metrics. But on a bright side, Prometheus has a dedicated Spring Boot integration so the same metrics could be exposed in Prometheus-compatible format, we are few beans away from that.

@Configuration
public class PrometheusConfig {
    @Bean
    public CollectorRegistry collectorRegistry() {
        return new CollectorRegistry();
    }

    @Bean
    public SpringBootMetricsCollector metricsCollector(
            final Collection<PublicMetrics> metrics, final CollectorRegistry registry) {
        return new SpringBootMetricsCollector(metrics).register(registry);
    }

    @Bean
    public ServletRegistrationBean exporterServlet(final CollectorRegistry registry) {
        return new ServletRegistrationBean(new MetricsServlet(registry), "/prometheus");
    }
}

With this configuration in place, metrics alternatively are going to be exposed under /prometheus endpoint, let us check this out.

> curl -u guest:guest http://localhost:19090/prometheus

# HELP cxf_services_Attribute_Data_Read_fifteenMinuteRate cxf_services_Attribute_Data_Read_fifteenMinuteRate
# TYPE cxf_services_Attribute_Data_Read_fifteenMinuteRate gauge
cxf_services_Attribute_Data_Read_fifteenMinuteRate 0.0
# HELP cxf_services_Attribute_Runtime_Faults_count cxf_services_Attribute_Runtime_Faults_count
# TYPE cxf_services_Attribute_Runtime_Faults_count gauge
cxf_services_Attribute_Runtime_Faults_count 0.0
# HELP cxf_services_Attribute_Totals_snapshot_stdDev cxf_services_Attribute_Totals_snapshot_stdDev
# TYPE cxf_services_Attribute_Totals_snapshot_stdDev gauge
cxf_services_Attribute_Totals_snapshot_stdDev 0.0
...

All the necessary pieces are covered and the fun time is about to begin. Prometheus has a very simple and straightforward installation steps but Docker is certainly the easiest one. The project repository includes docker-compose.yml file in docker folder to get you started quickly. But before, let us build the Docker image of our Spring Boot application using Apache Maven:

> mvn clean install

Upon successful build, we are ready to use Docker Compose tool to start all the containers and wire them together, for example:

> cd docker
> docker-compose up

Recreating docker_cxf_1
Recreating docker_prometheus_1
Recreating docker_grafana_1
Attaching to docker_cxf_1, docker_prometheus_1, docker_grafana_1
...

If you are using native Docker packages, just open your browser at http://localhost:9090/targets where you could see that Prometheus has successfully connected to our application and is consuming its metrics (for older Docker installations, please use the address of your Docker Machine).

The cxf target came preconfigured from Prometheus configuration file, located at docker/prometheus.yml and used to build the respective container in the docker-compose.yml (please notice the presence of the credentials to access /prometheus endpoint):

# my global config
global:
  scrape_interval:     15s # By default, scrape targets every 15 seconds.
  evaluation_interval: 15s # By default, scrape targets every 15 seconds.

scrape_configs:
  - job_name: 'cxf'

    # Override the global default and scrape targets from this job every 5 seconds.
    scrape_interval: 5s

    basic_auth:
      username: guest
      password: guest

    metrics_path: '/prometheus'

    # Default scheme is http
    static_configs:
      - targets: ['cxf:19090']

Prometheus supports graph visualizations but Grafana is unquestionable leader in mastering beautiful dashboards. It needs a bit of configuration though which could be done over web UI or, even better, through API . The data source is the most important one, and in our case should point to running Prometheus instance.

> curl 'http://admin:admin@localhost:3000/api/datasources' -X POST -H 'Content-Type: application/json;charset=UTF-8' --data-binary '{"name": "prometheus", "type": "prometheus", "url":"http://prometheus:9090", "access":"proxy", "isDefault":true}'

Done! Adding a sample dashboard is the next thing to do and again, API is the best way to accomplish that (assuming you are still in the docker folder)

> curl 'http://admin:admin@localhost:3000/api/dashboards/db' -X POST -H 'Content-Type: application/json;charset=UTF-8' --data-binary @cxf-dashboard.json

The same rule applies here, if you are still using Docker Machine, please replace localhost with appropriate virtual machine address. Also please notice that you have to do this only once when the containers are created first time. The configuration will be kept for existing containers.

To finish up, let us open our custom Grafana dashboard by navigating to http://localhost:3000/dashboard/db/cxf-services, using admin/admin as default credentials. Surely, you are going to see no data at first but by generating some load (f.e. using siege), we could have gotten interesting graphs to analyze, for example:

Those graphs were made simple (and not so much useful to be honest) on purpose, just to demonstrate how easy it is to collect and visualize metrics from your Apache CXF-based JAX-RS APIs in real-time. There are so many useful metrics our applications could expose that no shortage of ideas here expected. Plus, Grafana allows to define quite sophisticated graphs and queries, worth of another article, but official documentation is a good point to start off.

Hope this post will encourage everyone to think seriously about monitoring your JAX-RS APIs by exposing, collecting and visualizing important metrics. This is just a beginning ...

The complete project sources are available on Github.

Saturday, July 23, 2016

When things may get out of control: circuit breakers in practice. Apache Zest and Akka.

In the previous post we have started the discussion about circuit breakers and why this pattern gained so much importance these days. We have learned about Netflix Hystrix, the most advanced circuit breaker implementation for JVM platform, and its typical integration scenarios. In this post we are going to continue exploring the other options available, starting from Apache Zest library.

Surprisingly, Apache Zest being certainly a gem, is not well-known and widely used. It is a framework for domain centric application development which aims to explore composite-oriented programming paradigm. Its roots go back to 2007, where it was born under another name, Qi4j (and became Apache Zest in 2015). It would require a complete book just to go through Apache Zest features and concepts, but what we are interested in is the fact that Apache Zest has simple circuit breaker implementation.

Let us use the same example to consume https://freegeoip.net/ REST(ful) web API and wrap the communication with this external service using CircuitBreaker from Apache Zest:

public class GeoIpService {
    private static final String URL = "http://freegeoip.net/";
    private final ObjectMapper mapper = new ObjectMapper();
    private final CircuitBreaker breaker = new CircuitBreaker(5, 1000 * 120);
 
    public GeoIpDetails getDetails(final String host) {
        try {
            if (breaker.isOn()) {
                GeoIpDetails details = mapper.readValue(get(host), GeoIpDetails.class);
                breaker.success();
                return details;
            } else {
                // Fallback to empty response
                return new GeoIpDetails();
            }
        } catch (final IOException ex) {
            breaker.throwable(ex);
            throw new RuntimeException("Communication with '" + URL + "' failed", ex);
        } catch (final URISyntaxException ex) {
            // Should never happen, but just trip circuit breaker immediately
            breaker.trip(); 
            throw new RuntimeException("Invalid service endpoint: " + URL, ex);
        }
    }

    private String get(final String host) throws IOException, URISyntaxException {
        return Request
            .Get(new URIBuilder(URL).setPath("/json/" + host).build())
            .connectTimeout(1000)
            .socketTimeout(3000)
            .execute()
            .returnContent()
            .asString();
    }
}

Essentially, this is as basic CircuitBreaker implementation as it could possible get. We configured it to have a threshold of 5 failures (which in our case means failing requests) and sleeping window of 2 minutes (120 * 1000 milliseconds). It becomes the responsibility of the application developer to report the successes and failures using success() and throwable(...) methods respectively, with the option to open the circuit breaker immediately using trip() method call. Please take a note that CircuitBreaker relies on Java synchronization mechanisms and is thread-safe.

Interestingly, the CircuitBreaker from Apache Zest uses a little bit different conventions: instead of operating on closed / open states, it treats them as on / off ones. Those are more familiar to most of us. And to finish up, basic JMX instrumentation is also available out of the box.

It requires a couple of lines to be added into the GeoIpService initialization (constructor f.e.) to register and expose managed beans:

public GeoIpService() throws Exception {
    final ObjectName name = new ObjectName("circuit-breakers", 
        "zest-circuit-breaker", "freegeoip.net");

    ManagementFactory
        .getPlatformMBeanServer()
        .registerMBean(new CircuitBreakerJMX(breaker, name), name);
}

Please do not hesitate to glance through official Apache Zest Circuit Breaker documentation, there are quite a few use cases you may found useful for your projects. The complete example is available on Github.

In case you are developing on JVM using Scala programming language, you are certainly a lucky one as there is native circuit breaker implementation available as part of Akka toolkit. For example, let us redesign our Geo IP service consumer as a typical Akka actor which is going to make HTTP call over to https://freegeoip.net/:

case class GeoIp(host: String)
case class GeoIpDetails(ip: String = "", countryCode: String = "", 
  countryName: String = "", latitude: Double = 0, longitude: Double = 0)

class GeoIpActor extends Actor with ActorLogging {
  import spray.json._
  import spray.json.DefaultJsonProtocol._
  
  implicit val materializer: ActorMaterializer = ActorMaterializer()
  
  import context.dispatcher
  import context.system
  
  val breaker = new CircuitBreaker(
    context.system.scheduler,
    maxFailures = 5,
    callTimeout = 15 seconds,
    resetTimeout = 2 minutes)
  
  def receive = {
    case GeoIp(host) => breaker
      .withCircuitBreaker(Http()
        .singleRequest(HttpRequest(uri = s"http://freegeoip.net/json/$host"))
        .flatMap {
          case HttpResponse(OK, _, entity, _) => Unmarshal(entity).to[GeoIpDetails]
          case _ => Future.successful(GeoIpDetails())
        }
      ) pipeTo sender()
  }
}

At this moment, the pattern undoubtedly is looking familiar to all of us. The only new option which Akka's CircuitBreaker brings on the table is overall call timeout: the execution will be considered as failed when it is not completed within this time period (certainly very handy addition to the circuit breaker capabilities). The withCircuitBreaker function takes care of managing the circuit breaker state around the wrapped block of the code.

The interactions with the GeoIpActor are no different from any other Akka actor:

implicit val system = ActorSystem("circuit-breakers")
implicit val timeout: Timeout = 5 seconds

val geoIp = system.actorOf(Props[GeoIpActor], "geo-ip-actor")
val result = (geoIp ? GeoIp("8.8.8.8")).mapTo[GeoIpDetails]
  
result andThen { 
  case Success(details) => log.info("GEO IP: {}", details)
  case Failure(ex) => log.error("Communication error", ex)
} 

By looking a bit deeper into CircuitBreaker documentation we could get some insights about its internals. There are actually three states the CircuitBreaker could be: open, closed and half-open. The presence of half-open state serves the purpose to perform just a single attempt to try out if the invocation is back to normal operations or not.

The code snippet looks perfect but one thing to keep in mind is how the Actor Model and absence of shared mutable state affects the circuit breaker state synchronization. To facilitate that, Akka's CircuitBreaker has a rich set of callback notifications (like onOpen, onHalfOpen, onClose) so the state changes could be broadcasted between actors. The complete project sources are available on Github.

For the curious readers, just a few closing notes about adoption of the circuit breaker implementations. Netflix Hystrix is the number one choice at the moment, particularly (but not only) because of superior support from Spring community. Obviously, Akka CircuitBreaker is a natural choice for Scala developers who build their applications on top of excellent Akka toolkit. Concerning Apache Zest Circuit Breaker, it could be used as-is (if you want to fully control the behavior) or be easily integrated as an useful extension into existing general-purpose clients. For example, Apache CXF allows to configure JAX-RS / JAX-WS clients with Failover feature, including the circuit breaker-based implementation: CircuitBreakerFailoverFeature.

Hope this series of posts extended a little bit your awareness about circuit breaker pattern and the state of its available implementations on the JVM platform. The repository with complete project samples is available on Github.

Stay resilient!