Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Building Your Next Microservice With Eclipse MicroProfile

DZone's Guide to

Building Your Next Microservice With Eclipse MicroProfile

This quick tutorial will show you how to build your next microservice with the recently updated Eclipse MicroProfile APIs.

· Integration Zone
Free Resource

Modernize your application architectures with microservices and APIs with best practices from this free virtual summit series. Brought to you in partnership with CA Technologies.

Eclipse MicroProfile has been gaining a lot of attention recently with the latest release, 1.2, as well as recent new additions, including Oracle.  This is a quick tutorial for building your next microservice with the MicroProfile APIs.

MicroProfile is built from core JavaEE technologies:

While adding to them a set of specifications that make your microservices ready for the cloud including:

These specifications together make up Eclipse MicroProfile 1.2, the third release of the APIs. So how do you use all of this? Since this is only a specification and not an implementation, you'll need to check vendor-specific requirements, but this is a quick guide to building your first application. In many cases, you'll continue to deploy a WAR file like you would with JavaEE. First, add the MicroProfile dependency to your project.

Maven:

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

Gradle:

dependencies {
  compileOnly 'org.eclipse.microprofile:microprofile:1.2'
}


This one dependency brings in all of the needed APIs to build your application, however, you may need to consult with your server's runtime to see if other dependencies are required. So what would a typical service look like?

  1. A JAX-RS Controller. Since we're exposing a REST API, we want a controller to handle the API calls.

  2. A Service of some kind. You need some backing component to generate or consume data. We're going to be using some mock data for now, just to explain the paradigm.

  3. Monitoring. We want to know how often this service is invoked, and how long each request takes.

  4. Configurability. We don't want the client specifying the data volume, we want to do it declaratively.

  5. Security. Need both declarative and business logic driven security to know how to respond to requests.

  6. Fault Tolerance.  We care about any services we consume and ensuring we can fail fast or be resilient.

First, we have our rest controller, which should look very familiar.

@Path("/api/books") // just a basic JAX-RS resource
@Counted // track the number of times this endpoint is invoked
public class BooksController {
 @Inject //use CDI to inject a service
 private BookService bookService;

 @GET
 @RolesAllowed("read-books")
 // uses common annotations to declare a role required
 public Books findAll() {
  return bookService.getAll();
 }
}

If we dive in further to the service, we can start to see how configurability works:

@ApplicationScoped
public class BookService {
 @Inject
 // JPA is not provided out of the box, but most providers support it at
 // some level.  worst case, create your own producer for the field
 private EntityManager entityManager;

 @Inject
 // use configuration to control how much data you want to supply at 
 // a given time
 @ConfigProperty(name = "max.books.per.page", defaultValue = "20")
 private int maxBooks;

 public Books getAll() {
  List < Book > bookList = entityManager
   .createQuery("select b from Book b", Book.class)
   .setMaxResults(maxBooks) // use that configuration to do a paginated look up
   .getResultList();
  return new Books(bookList);
 }
}


Next, let's suppose we also want to handle the creation of books, the publication process. A service to support that may look like this:

@RequestScoped
public class PublishBookService {
 @Inject
 // we can inject a JsonWebToken, a Principal specific to the JWT specification
 private JsonWebToken jsonWebToken;
 // we could also inject individual ClaimValue objects.
 @Inject
 private AuthorService authorService;
 @Inject
 private EntityManager entityManager;
 @Timeout(500)
 // we want to limit how long it takes to publish and if it 
 // exceeds, return an exception to the caller.
 public BookId publish(PublishBook publishBook) {
  // we check the standard claim of subject 
  if (!publishBook.getAuthor().equals(jsonWebToken.getSubject())) {
   // as well as a custom claim as a boolean
   boolean createAny = jsonWebToken.getClaim("create.books.for.other.authors");
   if (!createAny) {
    throw new NotAuthorizedException("Cannot create book, wrong author");
   }
  }
  Author author = authorService.findAuthor(publishBook.getAuthor());
  if (author == null) {
   throw new NotAuthorizedException("The list author is not an author");
  }
  Book book = entityManager.merge(new Book(publishBook.getIsbn(), 
                                           publishBook.getAuthor()));
  return new BookId(book.getIsbn(), book.getAuthor());
 }
}

The last part, if we consider that managing authors is a separate bounded context, we want that to be represented as a discreet service. As a result, we want a client to that remote server to check that the author exists.

@ApplicationScoped
public class AuthorService {
 @Inject //inject a configuration property for the URL to the remote service
 @ConfigProperty(name = "author.service.url")
 private String authorUrl;

 private ConcurrentMap < String, Author > authorCache = new ConcurrentHashMap < > ();

 @Retry
 // indicate that this should trigger a retry in case the remote server
 // is unavailable or at capacity
 @CircuitBreaker
 // We also wrap the invocation in a circuit breaker, it will eventually 
 @Fallback(fallbackMethod = "getCachedAuthor")
 // indicate that we should fallback to the local cache
 public Author findAuthor(String id) {
  // in MicroProfile 1.3 we'll be including a type safe rest client, 
  // to make this setup even easier!
  Author author = ClientBuilder.newClient()
   .target(authorUrl)
   .path("/{id}")
   .resolveTemplate("id", id)
   .request(MediaType.APPLICATION_JSON)
   .get(Author.class);
  // ideally we want to read from the remote server.  However, we can build 
  // a cache as a fallback when the server is down
  authorCache.put(id, author);
  return author;
 }
 public Author getCachedAuthor(String id) {
  return authorCache.get(id);
 }
}


So there you have it! A couple of rest controllers, services, and you have a microservice built with Eclipse MicroProfile to manage books. You can download this sample code on GitHub.

The Integration Zone is proudly sponsored by CA Technologies. Learn from expert microservices and API presentations at the Modernizing Application Architectures Virtual Summit Series.

Topics:
microprofile ,javaee ,microservices ,integration ,eclipse

Published at DZone with permission of John Ament. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}