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
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Spring: Microservices with Spring Boot

You're reading from   Spring: Microservices with Spring Boot Build and deploy microservices with Spring Boot

Arrow left icon
Product type Paperback
Published in Mar 2018
Publisher
ISBN-13 9781789132588
Length 140 pages
Edition 1st Edition
Languages
Tools
Arrow right icon
Author (1):
Arrow left icon
In28Minutes Official In28Minutes Official
Author Profile Icon In28Minutes Official
In28Minutes Official
Arrow right icon
View More author details
Toc

First REST Service

Let's start with creating a simple REST service returning a welcome message. We will create a simple POJO WelcomeBean class with a member field called message and one argument constructor, as shown in the following code snippet:

    package com.mastering.spring.springboot.bean;

    public class WelcomeBean {
      private String message;

       public WelcomeBean(String message) {
         super();
         this.message = message;
       }

      public String getMessage() {
        return message;
      }
    }

Simple Method Returning String

Let's start with creating a simple REST Controller method returning a string:

    @RestController
    public class BasicController {
      @GetMapping("/welcome")
      public String welcome() {
        return "Hello World";
      }
    }

A few important things to note are as follows:

  • @RestController: The @RestController annotation provides a combination of @ResponseBody and @Controller annotations. This is typically used to create REST Controllers.
  • @GetMapping("welcome"): @GetMapping is a shortcut for @RequestMapping(method = RequestMethod.GET). This annotation is a readable alternative. The method with this annotation would handle a Get request to the welcome URI.

If we run Application.java as a Java application, it would start up the embedded Tomcat container. We can launch up the URL in the browser, as shown in the following screenshot:

Simple Method Returning String

Unit Testing

Let's quickly write a unit test to test the preceding controller method:

    @RunWith(SpringRunner.class)
    @WebMvcTest(BasicController.class)
    public class BasicControllerTest {

      @Autowired
      private MockMvc mvc;

      @Test
      public void welcome() throws Exception {
        mvc.perform(
        MockMvcRequestBuilders.get("/welcome")
       .accept(MediaType.APPLICATION_JSON))
       .andExpect(status().isOk())
       .andExpect(content().string(
       equalTo("Hello World")));
      }
    }

In the preceding unit test, we will launch up a Mock MVC instance with BasicController. A few quick things to note are as follows:

  • @RunWith(SpringRunner.class): SpringRunner is a shortcut to the SpringJUnit4ClassRunner annotation. This launches up a simple Spring context for unit testing.
  • @WebMvcTest(BasicController.class): This annotation can be used along with SpringRunner to write simple tests for Spring MVC controllers. This will load only the beans annotated with Spring-MVC-related annotations. In this example, we are launching a Web MVC Test context with the class under test being BasicController.
  • @Autowired private MockMvc mvc: Autowires the MockMvc bean that can be used to make requests.
  • mvc.perform(MockMvcRequestBuilders.get("/welcome").accept(MediaType.APPLICATION_JSON)): Performs a request to /welcome with the Accept header value application/json.
  • andExpect(status().isOk()): Expects that the status of the response is 200 (success).
  • andExpect(content().string(equalTo("Hello World"))): Expects that the content of the response is equal to "Hello World".

Integration Testing

When we do integration testing, we would want to launch the embedded server with all the controllers and beans that are configured. This code snippet shows how we can create a simple integration test:

    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = Application.class, 
    webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    public class BasicControllerIT {

      private static final String LOCAL_HOST = 
      "http://localhost:";

      @LocalServerPort
      private int port;

      private TestRestTemplate template = new TestRestTemplate();

      @Test
      public void welcome() throws Exception {
        ResponseEntity<String> response = template
       .getForEntity(createURL("/welcome"), String.class);
        assertThat(response.getBody(), equalTo("Hello World"));
       }

      private String createURL(String uri) {
        return LOCAL_HOST + port + uri;
      }
    }

A few important things to note are as follows:

  • @SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT): It provides additional functionality on top of the Spring TestContext. Provides support to configure the port for fully running the container and TestRestTemplate (to execute requests).
  • @LocalServerPort private int port: The SpringBootTest would ensure that the port on which the container is running is autowired into the port variable.
  • private String createURL(String uri): The method to append the local host URL and port to the URI to create a full URL.
  • private TestRestTemplate template = new TestRestTemplate(): The TestRestTemplate is typically used in integration tests. It provides additional functionality on top of RestTemplate, which is especially useful in the integration test context. It does not follow redirects so that we can assert response location.
  • template.getForEntity(createURL("/welcome"), String.class): It executes a get request for the given URI.
  • assertThat(response.getBody(), equalTo("Hello World")): It asserts that the response body content is "Hello World".

Simple REST Method Returning an Object

In the previous method, we returned a string. Let's create a method that returns a proper JSON response. Take a look at the following method:

    @GetMapping("/welcome-with-object")
    public WelcomeBean welcomeWithObject() {
      return new WelcomeBean("Hello World");
    }

This preceding method returns a simple WelcomeBean initialized with a message: "Hello World".

Executing a Request

Let's send a test request and see what response we get. The following screenshot shows the output:

Executing a Request

The response for the http://localhost:8080/welcome-with-object URL is shown as follows:

    {"message":"Hello World"}

The question that needs to be answered is this: how does the WelcomeBean object that we returned get converted into JSON?

Again, it's the magic of Spring Boot auto-configuration. If Jackson is on the classpath of an application, instances of the default object to JSON (and vice versa) converters are auto-configured by Spring Boot.

Unit Testing

Let's quickly write a unit test checking for the JSON response. Let's add the test to BasicControllerTest:

    @Test
    public void welcomeWithObject() throws Exception {
      mvc.perform(
       MockMvcRequestBuilders.get("/welcome-with-object")
      .accept(MediaType.APPLICATION_JSON))
      .andExpect(status().isOk())
      .andExpect(content().string(containsString("Hello World")));
    }

This test is very similar to the earlier unit test except that we are using containsString to check whether the content contains a substring "Hello World". We will learn how to write proper JSON tests a little later.

Integration Testing

Let's shift our focus to writing an integration test. Let's add a method to BasicControllerIT, as shown in the following code snippet:

    @Test
    public void welcomeWithObject() throws Exception {
      ResponseEntity<String> response = 
      template.getForEntity(createURL("/welcome-with-object"), 
      String.class);
      assertThat(response.getBody(), 
      containsString("Hello World"));
    }

This method is similar to the earlier integration test except that we are asserting for a sub-string using the Stringmethod.

Get Method with Path Variables

Let's shift our attention to path variables. Path variables are used to bind values from the URI to a variable on the controller method. In the following example, we want to parameterize the name so that we can customize the welcome message with a name:

    private static final String helloWorldTemplate = "Hello World, 
    %s!";

   @GetMapping("/welcome-with-parameter/name/{name}")
   public WelcomeBean welcomeWithParameter(@PathVariable String name) 
    {
       return new WelcomeBean(String.format(helloWorldTemplate, name));
    }

A few important things to note are as follows:

  • @GetMapping("/welcome-with-parameter/name/{name}"): {name} indicates that this value will be the variable. We can have multiple variable templates in a URI.
  • welcomeWithParameter(@PathVariable String name): @PathVariable ensures that the variable value from the URI is bound to the variable name.
  • String.format(helloWorldTemplate, name): A simple string format to replace %s in the template with the name.

Executing a Request

Let's send a test request and see what response we get. The following screenshot shows the response:

Executing a Request

The response for the http://localhost:8080/welcome-with-parameter/name/Buddy URL is as follows:

    {"message":"Hello World, Buddy!"}

As expected, the name in the URI is used to form the message in the response.

Unit Testing

Let's quickly write a unit test for the preceding method. We would want to pass a name as part of the URI and check whether the response contains the name. The following code shows how we can do that:

    @Test
    public void welcomeWithParameter() throws Exception {
      mvc.perform(
      MockMvcRequestBuilders.get("/welcome-with-parameter/name/Buddy")
     .accept(MediaType.APPLICATION_JSON))
     .andExpect(status().isOk())
     .andExpect(
     content().string(containsString("Hello World, Buddy")));
    }

A few important things to note are as follows:

  • MockMvcRequestBuilders.get("/welcome-with-parameter/name/Buddy"): This matches against the variable template in the URI. We pass in the name Buddy.
  • .andExpect(content().string(containsString("Hello World, Buddy"))): We expect the response to contain the message with the name.

Integration Testing

The integration test for the preceding method is very simple. Take a look at the following test method:

    @Test
    public void welcomeWithParameter() throws Exception {
      ResponseEntity<String> response = 
      template.getForEntity(
      createURL("/welcome-with-parameter/name/Buddy"), String.class);
      assertThat(response.getBody(), 
      containsString("Hello World, Buddy"));
    }

A few important things to note are as follows:

  • createURL("/welcome-with-parameter/name/Buddy"): This matches against the variable template in the URI. We are passing in the name, Buddy.
  • assertThat(response.getBody(), containsString("Hello World, Buddy")): We expect the response to contain the message with the name.

In this section, we looked at the basics of creating a simple REST service with Spring Boot. We also ensured that we have good unit tests and integration tests. While these are really basic, they lay the foundation for more complex REST services we will build in the next section.

The unit tests and integration tests we implemented can have better asserts using a JSON comparison instead of a simple substring comparison. We will focus on it in the tests we write for the REST services we will create in the next sections.

You have been reading a chapter from
Spring: Microservices with Spring Boot
Published in: Mar 2018
Publisher:
ISBN-13: 9781789132588
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