
Representational State Transfer (REST)
This is used for the purpose of data communication across web APIs. The REST API works pretty much in the same way as a website: you make a call from the client to the server and get a HTTP response back. REST uses HTTP methods to interact with the client and the server. REST allows a variety of data formats such as JSON or XML. It is generally faster and uses less bandwidth. It is also easy to integrate with other applications.
Commonly used HTTP methods in REST APIs include the following:
- GET: This is used for retrieving a data through APIs. It is a read-only method. It is safe to use duplicate GET methods.
- PUT: This is used to change or update a data using APIs. It is a write method, and we can use duplicate PUT methods.
- POST: This is used to create or insert data. It is a write method.
- DELETE: This is used to remove a particular piece of data.
Any web service that uses a REST architecture is called a RESTful API or a REST API.
Let's take an example of a Packt Publishing application developed with a microservices architecture. In this example, each microservice is focused on single business capability. PacktBookBase, PacktAuthorBase, PacktReaderBase, and PacktBookBase each have their instance (server) and communicate with one another. In the startup of Spring Boot, we need to add the following dependencies:
<parent
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId><version>1.2.0.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
</dependencies>
To enable the discovery client, we should add the preceding annotation to the PacktPubApplication class. This will make the service discoverable by the client.
The PacktPubApplication class will look as follows:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@EnableDiscoveryClient
@SpringBootApplication
public class PacktPubApplication
{
public static void main(String[] args)
{
SpringApplication.run(PacktPubApplication.class, args);
}
}
The preceding class will be the same for both the PacktAuthorBase and the PacktReaderBase projects since PacktBookBase consumes these services.
The class to use in the PacktAuthorBase project is as follows. This will be our REST service to search the authors:
package com.example.demo;
import javax.inject.Named;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class PacktPubApplication
{
@Named
static class JerseyConfig extends ResourceConfig
{
public JerseyConfig()
{
this.packages(“com.example.demo”);
}
}
@Bean
public RestTemplate restTemplate()
{
RestTemplate restTemplate = new RestTemplate();
return restTemplate;
}
}
Let's create our first service, PackAuthorBase, which basically gives us all the details about the author, along with their email IDs. Later, we call this PackAutherBase service through our mail service, PackBookBase. Let's see what it looks like:
package com.example.demo;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Named;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
@Named
@Path(“/”)
public class PacktAuthorBase
{
private static List<Author> clients = new ArrayList<Author>();
static
{
Author Author1 = new Author();
Author1.setId(1);
Author1.setName(“PackAuthor 1”);
Author1.setEmail(“Author1@hotmail.com”);
Author Author2 = new Author();
Author2.setId(2);
Author2.setName(“PackAuthor 2”);
Author2.setEmail(“Author2@hotmail.com”);
clients.add(Author1);
clients.add(Author2);
}
@GET
@Produces(MediaType.APPLICATION_JSON)
public List<Author> getClientes()
{
return clients;
}
@GET
@Path(“Author”)
@Produces(MediaType.APPLICATION_JSON)
public Author getCliente(@QueryParam(“id”) long id)
{
Author cli = null;
for (Author a : clients)
{
if (a.getId() == id)
cli = a;
}
return cli;
}
}
Now, let's create a new class called the Reader class, which will help the reader to search for books through their id, sku, or description. The reader class will look as follows:
package com.example.demo;
public class Reader
{
private long id;
private String sku;
private String description;
public long getId()
{
return id;
}
public void setId(long id)
{
this.id = id;
}
public String getSku()
{
return sku;
}
public void setSku(String sku)
{
this.sku = sku;
}
public String getDescription()
{
return description;
}
public void setDescription(String description)
{
this.description = description;
}
}
Let's create one more service, PacktReaderBase, which will have all the readers' data, along with their ID, sku, and description. Here, we import a few predefined namespaces such as core.MediaType to get a list of media types, QueryParams (to integrate the URI query parameter into our method), the arraylist, and other namespaces:
package com.example.demo;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Named;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
@Named
@Path(“/”)
public class PacktReaderBase
{
private static List<Reader> Readers = new ArrayList<Reader>();
static
{
Reader reader1 = new Reader();
reader1.setId(1);
reader1.setSku(“packpub1”);
reader1.setDescription(“Reader1”);
Reader reader2 = new Reader();
reader2.setId(2);
reader2.setSku(“packpub2”);
reader2.setDescription(“Reader2”);
Readers.add(reader1);
Readers.add(reader2);
}
@GET
@Readers(MediaType.APPLICATION_JSON)
public List<Reader> getProdutos()
{
return Readers;
}
@GET
@Path(Reader)
@Readers(MediaType.APPLICATION_JSON)
public Reader getProduto(@QueryParam(“id”) long id)
{
Reader prod = null;
for (Reader r : re)
{
if (r.getId() == id)
prod = r;
}
return prod;
}
}
Let's create our main class that will consume all the other services called PacktBookBase as follows:
package com.example.demo;
import java.util.Date;
import javax.inject.Inject;
import javax.inject.Named;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import org.springframework.web.client.RestTemplate;
@Named
@Path(“/”)
public class PacktBookBase
{
private static long id = 1;
@Inject
private RestTemplate restTemplate;
@GET
@Path(“book”)
@Produces(MediaType.APPLICATION_JSON)
public book submitbook(@QueryParam(“idAuthor”) long idAuthor,
@QueryParam(“idProduct”) long idProduct,
@QueryParam(“amount”) long amount)
{
book book = new book();
Author Author = restTemplate.getForObject
(“http://localhost:9001/Author?id={id}”, Author.class,idAuthor);
Reader reader = restTemplate.getForObject
(“http://localhost:9002/reader?id={id}”, Reader.class,idProduct);
book.setAuthor(Author);
book.setReader(Reader);
book.setId(id);
book.setAmount(amount);
book.setbookDate(new Date());
id++;
return book;
}
}
We have now completed the coding part, so let's try to run this application and test it. First, we need to start our REST services. Start the PacktAuthorBase service on port 9001, the PacktReaderBase in 9002, and the PacktBookBase on port 9003. We need to verify the following ports and see whether they are running:
- Dserver.port=9001
- Dserver.port=9002
After restarting the services, open the browser or Postman to test our code. We can test the PacktAuthorBase service by going through the following link:
http://localhost:9001/
This will return the response in JSON format, as follows:
[{"id":1,"name":"PackAuthor 1","email":"Author1@hotmail.com"},{"id":2,"name":"PackAuthor 2","email":"Author2@hotmail.com"}}]
As you can see, the response consists of all the registered authors as per our code base. It shows that the PacktAuthorBase service is working properly. We can also test this service by another method, where we can only return one particular author's details, as follows:
http://localhost:9001/Author?id=2
This returns a JSON with the author's data:
{
"id":2,
"name":"PackAuthor 2",
"email":"Author2@hotmail.com"
}
Similarly, to test whether the PacktReaderBase service is functioning properly, call the following URL:
http://localhost:9002/
This produces the following result in JSON:
[{"id":1,"item":"packpub1","Description":"Reader1"},{"id":2,"item":"packpub2","Description":"Reader2"}}]
Let's test the functionality of our final service: PacktBookBase. We will make an API call to get the author whose ID is 2, the product with an ID of 1, and the amount of 4:
http://localhost:9003/book?idAuthor=2&idProduct=3&amount=4
We produce the following JSON, which represents the header of a book:
{"id":1,"amount":4,"bookDate":1419530726399,"Author":{"id":2,"name":"PackAuthor 2","email":"Author2@hotmail.com"},"reader":{"id":1,"sku":"packpub1","Description":"Reader1"}
With a simple but powerful implementation, Spring Boot is a good option to implement a microservices architecture.