Writing microservices with WildFly Swarm
WildFly Swarm is a J2EE application packaging framework from RedHat that utilizes the in-memory Undertow server to deploy microservices. In this recipe, we will create the same GeoLocation
API using WildFly Swarm and JAX-RS.
To avoid confusion and dependency conflicts in our project, we will create the WildFly Swarm microservice as its own Maven project. This recipe is just here to help you get started on WildFly Swarm. When you are building your production-level application, it is your choice to either use Spring Boot, WildFly Swarm, Dropwizard, or SparkJava based on your needs.
Getting ready
Similar to how we created the Spring Boot Maven project, create a Maven WAR module with the groupId
com.packt.microservices
and name/artifactId
geolocation-wildfly
. Feel free to use either your IDE or the command line. Be aware that some IDEs complain about a missing web.xml
file. We will see how to fix that in the next section.
How to do it...
- Before we set up the WildFly Swarm project, we have to fix the missing
web.xml
error. The error message says that Maven expects to see aweb.xml
file in your project as it is a WAR module, but this file is missing in your project. In order to fix this, we have to add and configuremaven-war-plugin
. Add the following code snippet to yourpom.xml
file'sproject
section:<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>2.6</version> <configuration> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> </plugins> </build>
- After adding the snippet, save your
pom.xml
file and perform a Maven update. Also, if you see that your project is using a Java version other than 1.8, follow the Creating a project template using STS and Maven recipe to change the Java version to 1.8. Again, perform a Maven update for the changes to take effect. - Now, let's add the dependencies required for this project. As we know that we will be exposing our APIs, we have to add the JAX-RS library. JAX-RS is the standard JSR-compliant API for creating RESTful web services. JBoss has its own version of JAX-RS. So let's add that dependency to the
pom.xml
file:<dependencies> <dependency> <groupId>org.jboss.spec.javax.ws.rs</groupId> <artifactId>jboss-jaxrs-api_2.0_spec</artifactId> <version>1.0.0.Final</version> <scope>provided</scope> </dependency> </dependencies>
Note
The one thing that you have to note here is the provided scope. The provided scope in general means that this JAR need not be bundled with the final artifact when it is built. Usually, the dependencies with provided scope will be available to your application either via your web server or application server. In this case, when Wildfly Swarm bundles your app and runs it on the in-memory Undertow server, your server will already have this dependency.
- The next step toward creating the
GeoLocation
API using Wildfly Swarm is creating the domain object. Use thecom.packt.microservices.geolocation.GeoLocation.java
file from the previous recipe. - Now that we have the domain object, there are two classes that you need to create in order to write your first JAX-RS web service. The first of those is the
Application
class. TheApplication
class in JAX-RS is used to define the various components that you will be using in your application. It can also hold some metadata about your application, such as yourbasePath
(orApplicationPath
) to all resources listed in thisApplication
class. In this case, we are going to use/geolocation
as ourbasePath
. Let's see how that looks:package com.packt.microservices.geolocation; import javax.ws.rs.ApplicationPath; import javax.ws.rs.core.Application; @ApplicationPath("/geolocation") public class GeoLocationApplication extends Application { public GeoLocationApplication() {} }
There are two things to note in this class; one is the
Application
class and the other is the@ApplicationPath
annotation-both of which we've already talked about. - Now let's move on to the
resource
class, which is responsible for exposing the APIs. If you are familiar with Spring MVC, you can compare Resource classes to Controllers. They are responsible for defining the API for any specific resource. The annotations are slightly different from that of Spring MVC. Let's create a new resource class calledcom.packt.microservices.geolocation.GeoLocationResource.java
that exposes a simpleGET
API:package com.packt.microservices.geolocation; import java.util.ArrayList; import java.util.List; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; @Path("/") public class GeoLocationResource { @GET @Produces("application/json") public List<GeoLocation> findAll() { return new ArrayList<>(); } }
All the three annotations,
@GET
,@Path
, and@Produces
, are pretty self explanatory.
Before we start writing the APIs and the service class, let's test the application from the command line to make sure it works as expected. With the current implementation, any GET
request sent to the /geolocation
URL should return an empty JSON array.
So far, we have created the RESTful APIs using JAX-RS. It's just another JAX-RS project:
- In order to make it a microservice using Wildfly Swarm, all you have to do is add the
wildfly-swarm-plugin
to the Mavenpom.xml
file. This plugin will be tied to the package phase of the build so that whenever the package goal is triggered, the plugin will create an uber JAR with all required dependencies. An uber JAR is just a fat JAR that has all dependencies bundled inside itself. It also deploys our application in an in-memory Undertow server. Add the following snippet to theplugins
section of thepom.xml
file:<plugin> <groupId>org.wildfly.swarm</groupId> <artifactId>wildfly-swarm-plugin</artifactId> <version>1.0.0.Final</version> <executions> <execution> <id>package</id> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin>
- Now execute the
mvn clean package
command from the project's root directory, and wait for the Maven build to be successful. If you look at the logs, you can see thatwildfly-swarm-plugin
will create the uber JAR, which has all its dependencies. You should see something like this in your console logs: - After the build is successful, you will find two artifacts in the target directory of your project. The
geolocation-wildfly-0.0.1-SNAPSHOT.war
file is the final WAR created by themaven-war-plugin
. Thegeolocation-wildfly-0.0.1-SNAPSHOT-swarm.jar
file is the uber JAR created by thewildfly-swarm-plugin
. Execute the following command in the same terminal to start your microservice:java -jar target/geolocation-wildfly-0.0.1-SNAPSHOT-swarm.jar
- After executing this command, you will see that Undertow has started on port number 8080, exposing the geolocation resource we created. You will see something like this:
- Execute the following cURL command in a separate terminal window to make sure our API is exposed. The response of the command should be
[]
, indicating there are no geolocations:curl http://localhost:8080/geolocation
- Now let's build the service class and finish the APIs that we started. For simplicity purposes, we are going to store the geolocations in a collection in the service class itself. In a real-time scenario, you will be writing repository classes or DAOs that talk to the database that holds your geolocations. Get the
com.packt.microservices.geolocation.GeoLocationService.java
interface from the previous recipe. We'll use the same interface here. - Create a new class called
com.packt.microservices.geolocation.GeoLocationServiceImpl.java
that extends theGeoLocationService
interface:package com.packt.microservices.geolocation; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class GeoLocationServiceImpl implements GeoLocationService { private static List<GeoLocation> geolocations = new ArrayList<> (); @Override public GeoLocation create(GeoLocation geolocation) { geolocations.add(geolocation); return geolocation; } @Override public List<GeoLocation> findAll() { return Collections.unmodifiableList(geolocations); } }
- Now that our service classes are implemented, let's finish building the APIs. We already have a very basic stubbed-out
GET
API. Let's just introduce the service class to the resource class and call thefindAll
method. Similarly, let's use the service's create method forPOST
API calls. Add the following snippet toGeoLocationResource.java
:private GeoLocationService service = new GeoLocationServiceImpl(); @GET @Produces("application/json") public List<GeoLocation> findAll() { return service.findAll(); } @POST @Produces("application/json") @Consumes("application/json") public GeoLocation create(GeoLocation geolocation) { return service.create(geolocation); }
- We are now ready to test our application. Go ahead and build your application. After the build is successful, run your microservice: let's try to create two geolocations using the
POST
API and later try to retrieve them using theGET
method. Execute the following cURL commands in your terminal one by one:curl -H "Content-Type: application/json" -X POST -d '{"timestamp": 1468203975, "userId": "f1196aac-470e-11e6-beb8-9e71128cae77", "latitude": 41.803488, "longitude": -88.144040}' http://localhost:8080/geolocation
- This should give you something like the following output (pretty-printed for readability):
{ "latitude": 41.803488, "longitude": -88.14404, "userId": "f1196aac-470e-11e6-beb8-9e71128cae77", "timestamp": 1468203975 } curl -H "Content-Type: application/json" -X POST -d '{"timestamp": 1468203975, "userId": "f1196aac-470e-11e6-beb8-9e71128cae77", "latitude": 9.568012, "longitude": 77.962444}' http://localhost:8080/geolocation
- This command should give you an output similar to the following (pretty-printed for readability):
{ "latitude": 9.568012, "longitude": 77.962444, "userId": "f1196aac-470e-11e6-beb8-9e71128cae77", "timestamp": 1468203975 }
- To verify whether your entities were stored correctly, execute the following cURL command:
curl http://localhost:8080/geolocation
- This should give you an output like this (pretty-printed for readability):
[ { "latitude": 41.803488, "longitude": -88.14404, "userId": "f1196aac-470e-11e6-beb8-9e71128cae77", "timestamp": 1468203975 }, { "latitude": 9.568012, "longitude": 77.962444, "userId": "f1196aac-470e-11e6-beb8-9e71128cae77", "timestamp": 1468203975 } ]
Whatever we have seen so far will give you a head start in building microservices with WildFly Swarm. Of course, there are tons of features that WildFly Swarm offers. Feel free to try them out based on your application needs. I strongly recommend going through the WildFly Swarm documentation for any advanced usages. If you already know that you are going to be using WildFly Swarm for your microservices, you can skip the rest of the recipes in this chapter and jump to next chapter. The final two recipes in this chapter will show you how to create microservices using Dropwizard and how to create RESTful APIs with SparkJava.