My IBM Log in Subscribe

Java Microservices with MicroProfile – RESTful APIs and Dependency Injection

2 October 2018

8 min read

For microservices-based Java apps, knowing how to create REST APIs is an essential skill. Eclipse MicroProfile makes it easier.

What are microservices and how do they break the existing monoliths into smaller, more easily scaled and managed application services? How does the communication between these microservice apps happen? How do they communicate with the external world? If you are a developer, I bet that I know your answer: REST APIs.

Specifically for microservices applications, Java EE provides the Java API for RESTful Web Services (JAX-RS) framework. With its annotations, HTTP-centric nature, and format independence supporting a wide variety of content types, JAX-RS helps build REST APIs on the Java EE platform. Along with the RESTful APIs, Context Dependency Injection (CDI) is equally important to manage the lifecycle of the application and to provide dependency injection. This is one of the most powerful specifications in Java EE.

In today’s installment of our Java Microservices from Spring Boot series, I will compare the implementation of two different Java microservices frameworks—Spring Boot and Eclipse MicroProfile—using our example storefront application.

 

Eclipse MicroProfile is optimized for developers to build microservices and cloud-native applications using enterprise Java. Using the available APIs in MicroProfile, developers can easily build small and efficient microservices with the power of traditional Java EE frameworks.

Quick recap of this Java Microservices series

In our last installment, we shared how we started our journey from Spring Boot to MicroProfile. In today’s installment, I’ll cover how we refactored our microservices with JAX-RS and CDI using Eclipse MicroProfile.

For those who may have joined late, this blog series is based on my team’s experience migrating our simple storefront application from a Spring Boot-based microservices to MicroProfile, an optimized microservices programming model for enterprise Java. It was originally coded using Spring Boot (source code) and migrated to MicroProfile (source code). Both the projects are hosted on GitHub with source code and full documentation.

NB: If you would like more background on Java microservices architectures:

You can also explore the Open Liberty guides to become a MicroProfile master.

Spring Boot or MicroProfile for Java microservices apps? Choose the path of least resistance

When developers are looking to transform an existing Java EE monolith application to microservices, they have lots of options. Spring developers lean towards Spring Boot, Scala developers prefer frameworks like Play, and developers using multiple languages like Java, JavaScript, and Groovy are inclined towards Vert.x. I am a Java developer and personally prefer Java over other languages. I came across Eclipse MicroProfile and found it beneficial to build next-generation Java micro services and cloud-native applications. 

The Spring Boot and MicroProfile frameworks have many of the same goals (i.e., you can do everything in MicroProfile that you can do in Spring Boot). Both of them are built on top of the same core APIs; even though there are differences in some of the APIs, the work they do is similar. Each of the frameworks have their own advantages. So, developers have freedom to choose and work with their preferred framework—Spring Boot or MicroProfile. 

With that preamble out of the way, let’s dive into the details of our migration story and see how our application BlueCompute, a simple storefront app (GitHub source) was built on Spring Boot and then later migrated to Eclipse MicroProfile, the Java EE microservices framework.

Microservices app with Spring Boot: REST APIs Example

With the Spring Boot framework, REST APIs are defined using Controller  classes. These classes are responsible for handling different HTTP requests. To identify those classes, the @RestControll erannotation is used. To specify the route, mapping is done using @RequestMapping . Annotations like @GetMapping @PostMapping @PutMapping @PatchMapping , and @DeleteMapping  are used to map HTTP requests. Custom HTTP status codes are specified using @ResponseStatus . Variables coming from the path are captured using @PathVariable  and query string parameters are captured using @RequestParam . To consume the JSON body and deserialize it, @RequestBody  is used. These are some of the annotations that are used in the example Spring Boot application. For more details, check out the BlueCompute – Spring implementation (GitHub).

Microservices app with Spring Boot: Dependency Injection Example

Inversion of Control (IC) is a software engineering principle most commonly used in object-oriented programming. It means that the control of the code is transferred to a framework or container. It can be done using various mechanisms—dependency injection is one among them. In our sample application, Inversion of Control is implemented using dependency injection. 

Dependency Injection is done using autowiring. All the required dependencies are annotated with @Autowired . In our application, autowiring is done byName . This means autowiring is based on the property’s name and Spring will look for the bean based on the name of the property. If the beans are of the same type, then the names can be specified using the @Qualifier  annotation.

Microservices app with MicroProfile: Example Java REST API using JAX-RS

The Java API specification for RESTful frameworks is used for developing REST APIs and exposing them via annotations. The path for the application, which is the base URI, is identified by @ApplicationPath . The path for the individual resource is specified using @Path . Annotations like @GET @PUT @POST , and @DELETE are used to map HTTP requests. The annotations @Produces  and @Consumes  are used for MIME media types. Variables coming from the path are captured using @PathParam  annotation and query string params are captured using @QueryParam . These are some of the annotations that are used in the example Java MicroProfile application. For more details, more check out the BlueCompute – MicroProfile implementation(GitHub).

Microservices app with MicroProfile: Context and Dependency Injection (CDI) Example

Contexts and Dependency Injection (CDI) is one of the most popular components in Java EE platform that simplifies application code. It provides required scopes to bind the objects to their well-defined contexts. One important feature is dependency injection. It allows developers to inject components into the application in a type-safe manner. In our example application, scopes like @ApplicationScoped @RequestScoped  are used to bind the objects appropriately; dependency injection is done by injecting the objects using @Inject  annotation. 

When we use the scope @ApplicationScoped , the instance is shared across all the interactions of the user within the application:

@ApplicationScoped
public class ItemService {
}

Where as when we use @RequestScoped , the instance is shared only in that particular HTTP request when the user interaction is done in CatalogService :

@RequestScoped
public class CatalogService {
       @Inject
       ItemService itemsRepo;
}

These are some of the annotations that are used in the example application. For more details, check out the BlueCompute – MicroProfile implementation (GitHub).

Our journey from Spring Boot to MicroProfile

With the Spring Boot/MicroProfile differences understood, now let’s look at how we transformed our application using the standard APIs provided by MicroProfile.

We need the Maven dependency shown below in our pom.xml  to build our Java application using MicroProfile:

<dependency>
    <groupId>org.eclipse.microprofile</groupId>
    <artifactId>microprofile</artifactId>
    <version>1.3</version>
    <scope>provided</scope>
    <type>pom</type>
</dependency>

In the server.xml  of WebSphere Liberty, we added the MicroProfile feature:

<featureManager>
      <feature>microprofile-1.3</feature>
</featureManager>

The beauty of the MicroProfile feature is its various APIs that helps us to build microservices from scratch and helps us deliver them on different runtimes. JAX-RS 2.0 and CDI 1.1 are included in the very first release of MicroProfile, as these are the basic APIs any Java EE microservice requires. It is really nice to have them all in one place and make use of them without worrying about dependencies.

Now let’s walk through the details on how the migration is done. From our example application, consider the Catalog Service in our simple storefront application. The model class Item  is as follows:

public class Item {
    private long id;
    private String name;
    private String description;
    private int price;
    private String imgAlt;
    private String img;
    private int stock;
    // snip...
}

We began with the JAX-RS controller. As noted earlier, JAX-RS is used for providing both standard Java client and server APIs for RESTful communication by MicroProfile applications.

Below is a sample before/after snippet that gives you an idea of how the migration was done. While doing this migration, as a developer, I felt that the JAX-RS annotations were easier to understand compared to the Spring Boot annotations. I also felt that the code is more readable with JAX-RS that is specified by MicroProfile.

BEFORE: Spring Boot

@SpringBootApplication
public class Application {

............................
............................

}

******************************************************

@RestController
public class CatalogController{
@RequestMapping(value = "/items", method = RequestMethod.GET)
@ResponseBody
List<Item> getInventory() {
  // Return all items in Inventory
}

@RequestMapping(value = "/items/{id}", method = RequestMethod.GET)
ResponseEntity<?> getById(@PathVariable long id) {
// Return all items by id
}
............................
............................

}

AFTER: MicroProfile

@ApplicationPath("/rest")
public class CatalogApplication extends Application {
............................
............................
}

***************************************************

@Path("/items")
@Produces(MediaType.APPLICATION_JSON)
public class CatalogService{
@GET
public List<Item> getInventory() {
  // Return all items in Inventory
}

@GET
@Path("{id}")
public Response getById(@PathParam("id") long id) {
  // Return all items by id
}

............................
............................

}

The next step is to define Context Dependency Injection managed classes, with CDI handling all of the type-safe dependency injection. CDI helps us to manage the lifecycle of our objects in our application. Let’s review how we did it in our application.

If we consider the Catalog  service in our example implementation, we have a class called ItemService which contains some functions, e.g., the findAll()  method that helps us to get all the items in the inventory. This class should be persistent and same instance should be used across multiple resources. This dependency injection can be done by CDI. By using CDI, the same instance of the class is injected into the application and used by it. In the Spring Boot implementation of our sample application, we used @Autowired  to inject the service class. The annotation @Service  shown below makes the class auto-wireable. Whereas in the MicroProfile implementation of our sample application, we used the @ApplicationScoped  annotation to achieve dependency injection using the @Inject  annotation.

BEFORE: Spring Boot

@Service
public class ItemService {

public List<Item> findAll() {
// Get all items from database
}

}

public class CatalogController {

    @Autowired
    ItemService itemsRepo;

    @RequestMapping(value = "/items", method = RequestMethod.GET)
    @ResponseBody
    List<Item> getInventory() {
        return itemsRepo.findAll();
    }
    .......................
    .......................

}

AFTER: MicroProfile

@ApplicationScoped
public class ItemService {

public List<Item> findAll() {
// Get all items from database
}

}

public class CatalogService {

    @Inject
    ItemService itemsRepo;

    @GET
    public List<Item> getInventory() {
        List<Item> items = null;
        items = itemsRepo.findAll();
        return items;
     }
    .......................
    .......................

}

Hurray, that’s it! Our code is ready to run on WebSphere Liberty

If you are interested, you can also see how we implemented a bunch of other features that comes with MicroProfile like Config, Fault Tolerance, Health Checks, Metrics, REST Client, Open API, Open Tracing, JSON-B along with JAX-RS and CDI. To run the whole application together, please check out BlueCompute – MicroProfile implementation (GitHub).

What’s next

In today’s world of microservices, developing RESTful APIs is an essential skill. JAX-RS is one of the most impressive REST API frameworks we have in Java EE; it helps us to build RESTful APIs of our choice using the annotations to simplify the development. Making the development of REST services easier is important! Similarly, having dependency injection is equally important in your Java EE applications. CDI allows you to manage the contexts and also helps you to inject the services in a type-safe manner. These two amazing features are enough to build a microservice—all you have to do is to use some simple annotations and add some dependency injection.

 

I found the Open Liberty guides to be a piece of cake—they are incredibly easy to understand and following them made my path easier. These are the ones I followed:

This blog demonstrated how we migrated our example application from Spring Boot to MicroProfile using JAX-RS and CDI. This is just the beginning; you can do lot more with Eclipse MicroProfile. For example, interesting specifications like Fault Tolerance, REST Client, Health Checks, Metrics, Open API, Open Tracing, and Config are part of Eclipse MicroProfile. We’ll return to these through this blogs series.

Our next installment will cover MicroProfile RestClient & JSON-B. Meanwhile, stay tuned and have a look at our source code available on GitHub. All the individual microservices in our simple storefront application can be run locally using Maven as well. So, it should be simple for you to import them and run them as-is locally. You can also run them on IBM Cloud and IBM Cloud Private.

 

Author

Hemankita Perabathini

Cloud Solution Architect

Related solutions

Related solutions

IBM webMethods Hybrid Integration

AI-powered automation scales agility across APIs, apps, events, files and B2B/EDI.

Explore IBM webMethods Hybrid Integration
Integration software and solutions

Unlock business potential with IBM integration solutions, which connect applications and systems to access critical data quickly and securely.

Explore cloud integration solutions
Cloud consulting services 

Unlock new capabilities and drive business agility with IBM cloud consulting services. Discover how to co-create solutions, accelerate digital transformation, and optimize performance through hybrid cloud strategies and expert partnerships.

Explore cloud services
Take the next step

 

IBM webMethods Hybrid Integration offers a unified interface and control plane for integration patterns, applications, APIs, B2B and files, and scales agility across locations, environments and teams.

 

 

Explore IBM webMethods Hybrid Integration See it in action