Creating RESTful Web Services

As a first step, let's create RESTful Web Services exposing some data to the calling clients. As mentioned before, the Jackson library, which is responsible for the serialization and deserialization of JSON messages, is automatically included in our classpath together with spring-boot-starter-web. Thanks to that, we don't have to do anything more than declare a model class, which is then returned or taken as a parameter by REST methods. Here's our sample model class, Person:

public class Person {

private Long id;
private String firstName;
private String lastName;
private int age;
private Gender gender;

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

//...
}

Spring Web provides some annotations for creating RESTful Web Services. The first of them is the @RestController annotation, which should be set on your controller bean class that is responsible for handling incoming HTTP requests. There is also the @RequestMapping annotation, which is usually used for mapping controller methods to HTTP. As you see in the following code fragment, it can be used on the whole controller class to set the request path for all methods inside it. We can use more specific annotations for the concrete HTTP methods such as @GetMapping or @PostMapping.  @GetMapping is the same as @RequestMapping with the parameter method=RequestMethod.GET. Two other commonly used annotations are @RequestParam and @RequestBody. The first binds path and query params to objects; the second maps input JSON to objects using the Jackson library:

@RestController
@RequestMapping("/person")
public class PersonController {

private List<Person> persons = new ArrayList<>();

@GetMapping
public List<Person> findAll() {
return persons;
}

@GetMapping("/{id}")
public Person findById(@RequestParam("id") Long id) {
return persons.stream().filter(it -> it.getId().equals(id)).findFirst().get();
}

@PostMapping
public Person add(@RequestBody Person p) {
p.setId((long) (persons.size()+1));
persons.add(p);
return p;
}

// ...
}

To be compatible with REST API standards, we should handle PUT and DELETE methods. After their implementation, our service performs all CRUD operations:

Method Path Description
GET /person Returns all existing persons
GET /person/{id} Returns person with the given id
POST /person Adds new person
PUT /person Updates existing person
DELETE /person/{id} Removes person from list using given id

 

Here's a fragment of a sample @RestController implementation with the DELETE and PUT methods:

@DeleteMapping("/{id}")
public void delete(@RequestParam("id") Long id) {
List<Person> p = persons.stream().filter(it -> it.getId().equals(id)).collect(Collectors.toList());
persons.removeAll(p);
}

@PutMapping
public void update(@RequestBody Person p) {
Person person = persons.stream().filter(it -> it.getId().equals(p.getId())).findFirst().get();
persons.set(persons.indexOf(person), p);
}

The controller code is really simple. It stores all data in the local java.util.List, which is obviously not a good programming practice. However, treat that as a simplification adopted for the purposes of the basic example. In the section Integrating application with database, in this chapter, I'll cover more advanced sample application that integrates with the NoSQL database. 

Probably some of you have experience with SOAP Web Services. If we had created a similar service using SOAP instead of REST, we would provide a WSDL file for the client with all service definitions described. Unfortunately, REST doesn't support such standard notation as WSDL. In the initial stage of RESTful Web Services, it was said that Web Application Description Language (WADL) would perform that role. But the reality is that many providers, including Spring Web, do not generate WADL files after application startup. Why am I mentioning this? Well, we have already finished our first microservice, which exposes some REST operations over HTTP. You have probably run this microservice from your IDE or using the java -jar command after building the fat JAR. If you didn't change the configuration properties inside the application.yml file, or did not set the -Dport option while running the application, it is available under http://localhost:2222. In order to enable others to call our API, we have two choices. We can share a document describing its usage or mechanisms for automatic API client generation. Or both of them. That's where Swagger comes in.