October 2, 2018 By Hemankita Perabathini 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 @RestControllerannotation 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 @DELETEare 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 ItemServicewhich 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.

Was this article helpful?
YesNo

More from Cloud

The power of embracing distributed hybrid infrastructure

2 min read - Data is the greatest asset to help organizations improve decision-making, fuel growth and boost competitiveness in the marketplace. But today’s organizations face the challenge of managing vast amounts of data across multiple environments. This is why understanding the uniqueness of your IT processes, workloads and applications demands a workload placement strategy based on key factors such as the type of data, necessary compute capacity and performance needed and meeting your regulatory security and compliance requirements. While hybrid cloud has become…

Serverless vs. microservices: Which architecture is best for your business?

7 min read - When enterprises need to build an application, one of the most important decisions their leaders must make is what kind of software development to use. While there are many software architectures to choose from, serverless and microservices architectures are increasingly popular due to their scalability, flexibility and performance. Also, with spending on cloud services expected to double in the next four years, both serverless and microservices instances should grow rapidly since they are widely used in cloud computing environments. While…

Seamless cloud migration and modernization: overcoming common challenges with generative AI assets and innovative commercial models

3 min read - As organizations continue to adopt cloud-based services, it’s more pressing to migrate and modernize infrastructure, applications and data to the cloud to stay competitive. Traditional migration and modernization approach often involve manual processes, leading to increased costs, delayed time-to-value and increased risk. Cloud migration and modernization can be complex and time-consuming processes that come with unique challenges; meanwhile there are many benefits to gen AI assets and assistants and innovative commercial models. Cloud Migration and Modernization Factory from IBM Consulting®…

IBM Newsletters

Get our newsletters and topic updates that deliver the latest thought leadership and insights on emerging trends.
Subscribe now More newsletters