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

The Minimal REST Client and Server

DZone's Guide to

The Minimal REST Client and Server

This article will walk you through creating a microservices application with Spring Boot, written with the least code possible.

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.

REST applications lie at the heart of microservices and Spring Boot obviates a lot of configuration code. This naturally begs the question: What is the minimal amount of code you have to write for a REST microservice? The answer turns out to be: Nothing or nearly nothing. We demonstrate this by working through an example.

First, we develop the domain object. We deliberately keep it simple as to not obscure the main point. We will define an Employee class with just one attribute: name. We have added JPA annotations since we will persist the object. Now, good practice requires that we add an argument bearing constructor to initialize the object, a matching pair of equals and hashcode, and maybe a toString method. To be sure your favorite IDE can generate all these. But not only does it clutter the code worse, if you ever add more attributes you have to delete these methods and regenerate the code. We avoid all this by using Lombok. At a derisory cost, Lombok will inject all this in the class binary, as you can see in the project explorer in Eclipse.

@Data
@NoArgs
Constructor
@Entity
@Table(name = "employee")
public class Employee {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;
  private String name;
  public Employee(String name) {
    this.name = name;
  }
}

Now we use Spring Data to define a repository to persists the object (we will use the embedded H2 database, but you are free to configure say MySQL as a database).

public interface EmployeeRepository extends CrudRepository < Employee,
 Long > {}

Note that we have just defined an interface and relied on Spring Data JPA to provide the implementations. Spring Data will craft a concrete set of operations, such as save(Employee), delete(Employee), find(Employee), find(Long id), findAll() and findByName(String name). See https://docs.spring.io/spring-data/jpa/docs/current/reference/html/.

Now we need to expose the repository as REST endpoints. Customarily, we would write a controller somewhat like this:

@RestController
public class EmployeeController {

  @Autowired
  EmployeeRepository repo;

  @RequestMapping(value = "/employeesAll", method = RequestMethod.GET)
  List < Employee > employeesAll() {
    return repo.findAll();

  }
}

This is unnecessary. As the documentation states:

In its core, REST defines that a system consists of resources that clients interact with. .. But implementing even the simplest tenet of REST web services for a multi-domain object system can be quite tedious and result in a lot of boilerplate code.

Spring Data REST builds on top of Spring Data repositories and automatically exports those as REST resources. It leverages hypermedia to allow clients to find functionality exposed by the repositories and integrates these resources into related hypermedia based functionality automatically.”

Bottom line: we can expose find All() method of the Employees repository via the REST endpoint GET /employees. Likewise, we can insert an employee via POST /employees Similarly GET /employees/{id} will expose the find(id) method and so on. All other methods will return a 405 Method Not Allowed. For a full description, see https://docs.spring.io/spring-data/rest/docs/current/reference/html/.

To summarize what we have so far: we defined a domain object and skipped writing its boilerplate methods with Lombok. We defined a repository interface and let Spring Data JPA provide the implementations of many standard methods. We then exposed this repository as REST endpoints by using Spring Data Rest, and again we let Spring take care of providing the endpoint implementations.

If you use a browser and go to http://localhost:7111/employees, you will see something like this:

{
 "_embedded": {
  "employees": [{
   "name": "Gita",
   "_links": {
    "self": {
     "href": "http://localhost:7111/employees/1"
    },
    "employee": {
     "href": "http://localhost:7111/employees/1"
    }
   }
  }, {
   "name": "Krishna",
   "_links": {
    "self": {
     "href": "http://localhost:7111/employees/2"
    },
    "employee": {
     "href": "http://localhost:7111/employees/2"
    }
   }
  }]
 },
 "_links": {
  "self": {
   "href": "http://localhost:7111/employees"
  },
  "profile": {
   "href": "http://localhost:7111/profile/employees"
  }
 }
}

Where we have persisted some sample data:

@Bean
InitializingBean saveData(final EmployeeRepository repo) {

  return new InitializingBean() {
   public void afterPropertiesSet() throws Exception {
    repo.save(new Employee("Gita"));
    repo.save(new Employee("Krishna"));
    System.out.println("Inserted data:" + repo.findAll());
   }

  };

Recall that the documentation said “It leverages hypermedia to allow clients to find functionality exposed by the repositories”. What we are seeing is HAL+JSon output. HAL is a specification to include hypermedia links in a JSON object (see http://stateless.co/hal_specification.html).

Now, onto the client. Surely now we need to write some code with RestTemplate and so on right? Nope. We can use Netflix Feign to create a client to the REST service with no code. Feign is a declarative REST client. To use it, all we have to do is to annotate the REST interface. Normally, we would use a fluent FeignBuilder to configure a JSON Encoder and decoder, but Spring Cloud Feign uses the default HttpMessageConverters used in Spring Web MVC.

@RestController
public class FeignController {

  @Autowired
  EmployeeServiceClient client;

  @RequestMapping("/employeeNames")
  List < String > getEmployeeNames() {

    return this.client.getEmployees().getContent().stream().map(Employee::getName).collect(Collectors.toList());
  }

  //The feign client whose implementation is provided by Feign
  @FeignClient(name = "EmployeeServiceClient", url = "http://localhost:7111")
  interface EmployeeServiceClient {

    @RequestMapping(value = "/employees", method = RequestMethod.GET, consumes = "application/hal+json")
    Resources < Employee > getEmployees();

  }

}

Note that we defined the Feign client using an interface and the getEmployees() method returns not an Employee JSON, but a HAL+JSON Employee with links. I have to admit this had me flummoxed for a while, until I saw Josh Long’s code on GitHub, from which I shamelessly copied my method. Now, if in a browser you do localhost:8080/employeeNames, you should see

["Gita","Krishna"]

That’s it. Of course, real-world domain objects are not this trivial, and you may have a lot more attributes, but using Lombok nothing changes. Also, you may have to add more custom methods to the repository interface. But as long as you follow a prescribed naming convention for the methods, Spring Data JPA will provide the implementation. It is nice that all this boilerplate comes gratis.

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:
jpa 2.0 ,rest ,integration ,spring boot ,microservices

Opinions expressed by DZone contributors are their own.

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

{{ parent.tldr }}

{{ parent.urlSource.name }}