Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Microservices Deployment Cookbook

You're reading from   Microservices Deployment Cookbook Deploy and manage scalable microservices

Arrow left icon
Product type Paperback
Published in Jan 2017
Publisher Packt
ISBN-13 9781786469434
Length 378 pages
Edition 1st Edition
Languages
Tools
Arrow right icon
Author (1):
Arrow left icon
Vikram Murugesan Vikram Murugesan
Author Profile Icon Vikram Murugesan
Vikram Murugesan
Arrow right icon
View More author details
Toc

Table of Contents (9) Chapters Close

Preface 1. Building Microservices with Java FREE CHAPTER 2. Containerizing Microservices with Docker 3. Deploying Microservices on Mesos 4. Deploying Microservices on Kubernetes 5. Service Discovery and Load Balancing Microservices 6. Monitoring Microservices 7. Building Asynchronous Streaming Systems with Kafka and Spark 8. More Clustering Frameworks - DC/OS, Docker Swarm, and YARN

Writing REST APIs with Spring MVC

There are two types of communication models. One of them is synchronous, where the client waits for the server to respond to its request. The other is asynchronous, where the client fires a request and forgets. Though Servlet 3.0 and above let you create asynchronous servlets, in our recipes, we will focus on traditional servlet-based HTTP APIs for simplicity. We will also be looking at asynchronous communication in later chapters.

Getting ready

When it comes to building REST APIs, there are several frameworks to choose from. As we already set up the Spring ecosystem in our previous recipe, it would make more sense and be much easier to use Spring MVC to expose REST APIs.

How to do it...

The true advantage of Spring Boot is that you do not have to add any new dependencies to enable web support for your application. Spring Boot's parent pom file (spring-boot-starter-parent) takes care of that for you. Now let's take a look at how to write our first API. If you are familiar with Spring MVC, this should be really straight-forward for you:

  1. Create a Controller class called com.packt.microservices.geolocation.GeoLocationController.java, which will be responsible for basic CRUD operations for the geolocation of all users:
            package com.packt.microservices.geolocation; 
     
            import org.springframework.web.bind.annotation.RequestMapping; 
            import org.springframework.web.bind.annotation.RestController; 
     
            @RestController 
            @RequestMapping("/geolocation") 
            public class GeoLocationController { 
     
            } 
    

    There are two things to note here. The @RestController annotation indicates that we are going to use this controller to expose our REST APIs. It implicitly adds the @ResponseBody annotation to all controller methods as that is something you would want to do when exposing your REST APIs using Spring MVC. The @RequestMapping annotation specifies where your HTTP resource is located. We are setting @RequestMapping on the controller level to apply it to all controller methods.

    Note

    Using @RequestMapping on the Controller class level to define a root resource path is considered to be one of the best practices. Instead of having to create API paths such as /getGeolocation or /createGeolocation, it is always a better practice to use the same path, /geolocation, with the GET method to get geolocation data and the POST method to create geolocation data.

  2. Before we jump into creating our APIs, we will need some classes for the domain object and service. Let's start with creating our domain object. Assume that our GeoLocation consists latitude and longitude. We will be defining both latitude and longitude as double to provide better precision. Now we will have to say which user's geolocation it is. So we might want to add a userId. We also need to say at what time the user was at the geolocation. So we might want to add a timestamp in EPOCH time format. The timestamp will be of type long. This is how your plain old java object (POJO) class will look:
            package com.packt.microservices.geolocation; 
    
            import java.io.Serializable; 
            import java.util.UUID; 
     
              public class GeoLocation implements Serializable { 
     
                private static final long serialVersionUID = 1L; 
       
               private double latitude; 
               private double longitude; 
               private UUID userId; 
               private long timestamp; 
       
              public double getLatitude() { 
                return latitude; 
              } 
       
              public void setLatitude(double latitude) { 
                this.latitude = latitude; 
              } 
       
              public double getLongitude() { 
               return longitude; 
              } 
       
              public void setLongitude(double longitude) { 
                this.longitude = longitude; 
              } 
       
              public UUID getUserId() { 
               return userId; 
              } 
       
              public void setUserId(UUID userId) { 
               this.userId = userId; 
              } 
       
             public long getTimestamp() { 
              return timestamp; 
             } 
       
             public void setTimestamp(long timestamp) { 
              this.timestamp = timestamp; 
             } 
            } 
    

    As you can see, we have used the java.util.UUID class to represent the userId, assuming that this UUID uniquely identifies a user. We will not be creating the user POJO as it is out of scope for this recipe.

    In an ideal scenario, one would be using a NoSQL or relational database to store the geolocations. In this case, NoSQL sounds more suitable due to several reasons, including the fact that our data is time series data, in JSON format, unstructured but will change over time and we will have a humongous amount of data.

  3. For simplicity purposes, we will be storing our geolocations in an in-memory java.util.List<GeoLocation> collection. Let's create our repository that holds all our geolocation objects, com.packt.microservices.geolocation.GeoLocationRepository.java:
            package com.packt.microservices.geolocation; 
     
            import java.util.ArrayList; 
            import java.util.Collections; 
            import java.util.List; 
     
            import org.springframework.stereotype.Repository; 
     
            @Repository 
            public class GeoLocationRepository { 
     
              private List<GeoLocation> geolocations = new
              ArrayList<GeoLocation>(); 
       
                public void addGeoLocation(GeoLocation geolocation) { 
                  geolocations.add(geolocation); 
                } 
       
               public List<GeoLocation> getGeoLocations() { 
                  return Collections.unmodifiableList(geolocations); 
               } 
             } 
    
  4. Now let's take a look at how your Service interface will look:
            package com.packt.microservices.geolocation; 
     
            import java.util.List; 
     
            public interface GeoLocationService { 
     
              public GeoLocation create(GeoLocation geolocation); 
              public List<GeoLocation> findAll(); 
            }  
    
  5. Both our repository and service have a very simple interface. Ideally in real-time applications, you might want to add more complicated methods that not only perform CRUD operations but also sort, filter, select only specific fields, and so on. Now let's take a look at our com.packt.microservices.geolocation.GeoLocationServiceImpl.java class:
            package com.packt.microservices.geolocation; 
     
            import java.util.List; 
     
            import org.springframework.beans.factory.annotation.Autowired; 
     
            import org.springframework.stereotype.Service; 
     
            @Service 
            public class GeoLocationServiceImpl implements
            GeoLocationService { 
       
              @Autowired 
              private GeoLocationRepository repository; 
     
              @Override 
              public GeoLocation create(GeoLocation geolocation) { 
               repository.addGeoLocation(geolocation); 
               return geolocation; 
              } 
     
              @Override 
              public List<GeoLocation> findAll() { 
                return repository.getGeoLocations(); 
              } 
            }

    Note

    It is always strongly recommended that you write unit test cases for any new code. But as that is a little out of scope for this book, we will not be writing unit test cases for any of the previous code. To learn more about unit testing Spring Boot applications, please take a look at Spring Boot's documentation at https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html.

  6. Now that our domain and service classes are all set to go, let's modify our Controller class to save and find geolocations. Add the following snippet into your Controller class body:
            @Autowired
            private GeoLocationService service;
    
            @RequestMapping(method = RequestMethod.POST, produces = "application/json", consumes = "application/json")
            public GeoLocation create(@RequestBody GeoLocation geolocation) {
              return service.create(geolocation);
            }
      
            @RequestMapping(method = RequestMethod.GET, produces = "application/json")
            public List<GeoLocation> findAll() {
              return service.findAll();
            } 
    

In this implementation, there are a few things to notice. The @RequestMapping annotation does not have a path defined as it is already derived from the class-level annotation. For both the create and findAll methods, we are using the same path but different HTTP methods as per best practice. Since we are dealing only with JSON here, we have set the produces and consumes values to application/json. The return types of the create and findAll methods are GeoLocation and List<GeoLocation> respectively. Spring MVC internally uses Jackson to convert them to their equivalent JSON strings.

That's it! We are now ready to test our application:

  1. Let's try to create two geolocations using the POST API and later try to retrieve them using the GET 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
    
  2. This should give you an output similar to the following (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
    
  3. This 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
            }
    
  4. To verify whether your entities were stored correctly, execute the following cURL command:
          curl http://localhost:8080/geolocation
    
  5. This should give you an output similar to the following (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 
            } 
            ]
    

You now have a fully working version of your microservice. The remaining recipes in this chapter try to achieve the same logic with different frameworks, such as WildFly Swarm and Dropwizard. Later in this chapter, we will also look at another framework that helps you build REST APIs quickly called SparkJava (different from Apache Spark). If you will be using Spring Boot for your microservices, you can jump to the next chapter. If you are interested in any of the frameworks that were mentioned, jump to the appropriate recipe in this chapter.

You have been reading a chapter from
Microservices Deployment Cookbook
Published in: Jan 2017
Publisher: Packt
ISBN-13: 9781786469434
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Banner background image