Creating REST API in Spring boot – Part4

In last post we had created a REST controller which will be consumed by the end user. So far controller’s method are empty. Controller is supposed to be using services in order to fetch data from DB layer and return them to user.

For creating service, a very general rule is to create a contract and then implementation of that contract. A contract defines functionality a service is supposed to provide. We can create an Interface for this purpose, as it just defines the functionality.

Why do we need an interface and not a class which implements all functionalities?

The implementation of the functionality may vary depending upon various cases and hence its wise to separate functions and its implementation.

Create an Interface named QuoteService as below.


public interface QuotesService {
// fetches list of quotes for given page and returns them
List<Quote> getQuotes(int page);

// fetches list of quotes for given topic and page and returns them
List<Quote> getQuotes(String quote, int page);

//fetches all available topics and returns them
List<Topic> getTopics();
}

How to do Pagination?

First of all we need to define max number of quotes which will be served in single page. Let’s create a constant field for this

private static final int MAX_QUOTES_PER_PAGE = 20;

So, we will be serving at max 20 quotes per page. Hence for first page quotes will be fetched from 0-19 and for second 20-39 etc.

In QuoteDB we have a function which takes an offset and count to return given number of quotes from given offset. Hence we need to find a way to calculate an offset for every page and we have already defined how many quotes we want per page (this is very trivial example of business logic)

For first page offset of-course will be 0 and fir next page it will be index after 19 feeds (considering 0th index) which is 0 + 20 = 20.

Hence offset can be defined as

offset = (page -1 ) * MAX_QUOTES_PER_PAGE

So we can implement our first getQuote method of pagination as below

public List<Quote> getQuotes(int page) {
int offset = (page-1) * MAX_QUOTES_PER_PAGE;
return db.getQuotes(offset, MAX_QUOTES_PER_PAGE);
}

db is instance of QuoteDB.

For topics we have to see if given string contains multiple topics or just one. If given multiple topics then we will fetch quotes for each topic one by one and add them into a set (for avoiding duplicates)

public List<Quote> getQuotes(String topic, int page) {
int offset = (page-1) * MAX_QUOTES_PER_PAGE;
if(topic == null || topic.trim().length() ==0) {
return Collections.emptyList();
}
if(topic.contains(",")) {
String[] topics = topic.split(",");
Set<Quote> quotes = new HashSet<>();
for(String t : topics) {
quotes.addAll(db.getQuotesFromTopic(t, offset, MAX_QUOTES_PER_PAGE));
}
return new ArrayList<>(quotes);
}
else {
return db.getQuotesFromTopic(topic, offset, MAX_QUOTES_PER_PAGE);
}
}

Fetching all topics won’t be tough

public List<Topic> getTopics() {
return db.getTopics();
}

Putting all together Below is concrete implementation of interface QuoteService

@Service
public class QuotesServiceImpl implements QuotesService {

private static final int MAX_QUOTES_PER_PAGE = 20;
private QuoteDB db;

QuotesServiceImpl() {
db = QuoteDB.getInstance();
}

/**
* Get Quotes for given page
* @param page
* @return
*/
@Override
public List<Quote> getQuotes(int page) {
int offset = (page-1) * MAX_QUOTES_PER_PAGE;
return db.getQuotes(offset, MAX_QUOTES_PER_PAGE);
}

/**
* Get quotes for given topics
* @param topic
* @param page
* @return
*/
@Override
public List<Quote> getQuotes(String topic, int page) {
int offset = (page-1) * MAX_QUOTES_PER_PAGE;
if(topic == null || topic.trim().length() ==0) {
return Collections.emptyList();
}
if(topic.contains(",")) {
String[] topics = topic.split(",");
Set<Quote> quotes = new HashSet<>();
for(String t : topics) {
quotes.addAll(db.getQuotesFromTopic(t, offset, MAX_QUOTES_PER_PAGE));
}
return new ArrayList<>(quotes);
}
else {
return db.getQuotesFromTopic(topic, offset, MAX_QUOTES_PER_PAGE);
}
}

/**
* Returns topics
* @return
*/
public List<Topic> getTopics() {
return db.getTopics();
}
}

@Service?

@Service annotation asks Spring to create service instance of this implementations. We are going to have just one implementation for this service, in case of multiple implementations we need to use qualifiers

For implementing above functionalities, we need to have instance of our QuoteDb. We can do that using QuoteDB.getInstance();

In Next post we will be using instance of this service in our rest controller to serve results to end user

Leave a comment

Your email address will not be published. Required fields are marked *