Using Feign to consume external REST API in Spring boot

Some time we need to consume external services in order to serve content to our users. In our quotes service also we can service users images for various topics as well. In order to do so i have used Pexels for fetching images. Pexels provide royalty free images. In order to consume Pexels API you need to obtain a developer API key. Please sign up for developer key from https://www.pexels.com/api

I suggest to go through the documentation of pexels API.

There are multiple way to consume external REST Api in Spring boot application. Netflix’s feign client is one of them and is quite easy to use. Spring boot provides integration with feign-client using spring cloud package. In order to use feign client update your pom.xml with below dependencies.

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>

Add property spring-cloud.version.

<spring-cloud.version>Finchley.SR1</spring-cloud.version>

Let’s create a contract for ImageService. And Image Pojo class

public class Image {
private final String source;
private final String photographer;
private final String photographerUrl;
private final String imageUrl;

  public Image(String source, String photographer, String imageUrl, String photographerUrl) {
this.source = source;
this.photographer = photographer;
this.imageUrl = imageUrl;
this.photographerUrl = photographerUrl;
}
//Getters and Setters
}

public interface ImageService {
//Returns random images pagewise
public List<Image> getImages(int page);

// Returns list of images for a topic
public List<Image> getImages(String topic, int page);
}

We have defined contract first because this function’s implementation may vary depending on sources. I have implemented this for Pexels you may use other (eg: unsplash)

Pexel provides response in its own format and we will have to re-transform response received pexel into our Image pojo. As these transformation is specific to pexel, we will create a concrete implementation of ImageService and will put all pexel related codes into it.

@Service
public class PexelsImageService implements ImageService {
@Override
  public List<Image> getImages(int page) {
return null;
}
@Override
  public List<Image> getImages(String topic, int page) { return null;}
}

As mentioned we will use Feign client to consume Pexel service. For creating feign client we need to define an interface. Interface will have methods corresponding to endpoint we are going to consume. As we will be consuming two end points, hence we will have two methods.

Also Feign client needs to be annotated with @FeignClient annotation. This annotation will take two params,

  1. Name: name of the client
  2. url: base url of the service

in application.properties define below property

pexel.search.uri=https://api.pexels.com/v1/search

Create either an inner interface within PexelService class or a completely new interface named PexelsClient and annotate it with @FeignClient as below

@FeignClient(name = "data", url = "${pexel.search.uri}")
private interface PexelsClient {

// for fetching images page by page. refer https://www.pexels.com/api/documentation/
@RequestMapping(method = RequestMethod.GET)
PexelsResponse getPhotos(@RequestParam("query") String query,
@RequestParam("per_page") int perPage,
@RequestParam("page") int page);

// for fetching images for a topic. refer https://www.pexels.com/api/documentation/
@RequestMapping(method = RequestMethod.GET)
PexelsResponse getPhotos(@RequestParam("per_page") int perPage,
@RequestParam("page") int page);
}

Spring on run time will create an implementation of feign-client and will create an instance of it. We can get instance of this feign client using @Autowire.

PexelResponse defines Pexel’s response format

Below is POJO classes which represents Pexel’s data format

private static class PexelsResponse {
private List<Photo> photos;

public List<Photo> getPhotos() {
return photos;
}

public void setPhotos(List<Photo> photos) {
this.photos = photos;
}
}

private static class Photo {
private String url;
private String photographer;
@SerializedName("photographer_url")
private String photographerUrl;
private ImageSrc src;

public String getUrl() {
return url;
}

public void setUrl(String url) {
this.url = url;
}

public String getPhotographer() {
return photographer;
}

public void setPhotographer(String photographer) {
this.photographer = photographer;
}

public String getPhotographerUrl() {
return photographerUrl;
}

public void setPhotographerUrl(String photographerUrl) {
this.photographerUrl = photographerUrl;
}

public ImageSrc getSrc() {
return src;
}

public void setSrc(ImageSrc src) {
this.src = src;
}
}

private static class ImageSrc {
private String large;

public String getLarge() {
return large;
}

public void setLarge(String large) {
this.large = large;
}
}

Now we have Feign client and we have defined Pexel’s response format. Our feign client will consume Pexel service and will return us response as instance of PexelFormat. Now let’s implement our PexelService’s methods

First of all we need to define how many images we will fetch per page. Like old time, let’s create a constant for this

private static final int MAX_IMAGES_PER_PAGE = 20;

We will obtain instance of feign client using @Autowire

@Autowired
private PexelsClient client;

For Image source let’s create a constant

private static final String PEXELS = "Pexels";

Below is implementation of getImage by page, (refer to the comments for explanation)

@Override
public List<Image> getImages(int page) {
// Returns images in pexel's format
PexelsResponse response = client.getPhotos(MAX_IMAGES_PER_PAGE, page);
List<Image> images = new ArrayList<>();
//Iterate through all pages
for(Photo photo : response.getPhotos()) {
// Create an instance of Image using each photo and add to list of Images
Image image = new Image(PEXELS, photo.getPhotographer(),
photo.getSrc().getLarge(), photo.getPhotographerUrl());
images.add(image);
}
// Return image list
return images;
}

Similarly we will implement getImages for topics as well

@Override
public List<Image> getImages(String topic, int page) {
PexelsResponse response = client.getPhotos(topic, MAX_IMAGES_PER_PAGE, page);
List<Image> images = new ArrayList<>();
for(Photo photo : response.getPhotos()) {
Image image = new Image(PEXELS, photo.getPhotographer(),
photo.getSrc().getLarge(), photo.getPhotographerUrl());
images.add(image);
}
return images;
}

This completes our PexelImageService. But we are still left with one part. With each pexel request we need to send our api key. The best way to include mandatory information in request is request interceptors. Feign client provides a convenient way of registering a request interceptor. All you need to do is to implement feign.RequestIntercptor and annotate it as @Component (spring component)

This interceptor will intercept each feign client’s request and make necessary modification (if required). Create a class PexelRequestInterceptor and implement feign.RequestInterceptor method

@Component
public class PexelRequestInterceptor implements RequestInterceptor {

@Value("${pexel.api.key}")
private String apiKey; // will fetch pexel's api key from Applictaion.properties
private static final String AUTHORIZATION = "Authorization";


@Override
public void apply(RequestTemplate requestTemplate) {
requestTemplate.header(AUTHORIZATION, apiKey);
//required as Pexel expect requests from a browser
requestTemplate.header("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 " +
"(KHTML, like Gecko) Chrome/23.0.1271.95 Safari/537.11");
}
}

Add your Pexels api key you obtained in application.property file with property name pexel.api.key

By now we should be able to fetch images from pexel’s server using instance of PexelImageService.

Let’s create an endpoint in Our QuoteResource rest controller and autowire instance of PexelImageService as type of ImageService

@RestController
public class QuotesResource {

@Autowired
private QuotesService service;

@Autowired
private ImageService imageService; // instance of PexelImageService

//Quote's endpoint


// Endpoint for fetching images
@GetMapping("/images")
  public List<Image> getImages(@RequestParam("topic") String topic
, @RequestParam(value= "page", required = false, defaultValue = "0") int page) {
if(topic == null || topic.trim().length() == 0) {
return imageService.getImages(page);
}
return imageService.getImages(topic, page);
}
}

Now restart spring application and hit url http://localhost:8080/images?topic=science&page=1

If everything done right, you should receive list of images in response.

Creating REST API in Spring boot – Part5

In Part4 we implemented our service layer which sits between controller and DB. Now we will use QuoteService to fetch data from QuoteDB to serve content to end user.

As we have annotated QueryServiceImpl as service component, we can ask spring to provide us an instance of this service. This is done by Dependency injection

One of the way to use dependency injection in spring is using annotation @Autowire. When spring boots it initializes all annotated components. If a member variable in annotated class is annotated with @Autowire then spring assign it the required instance (if available, otherwise process fails to start).

We will use @Autowire to get instance of our QuoteService. We can do this as below

@Autowired
private QuotesService service;

Now we can implement our first end point for fetching quotes page by page as below

@GetMapping("/quotes/{page}")
public List<Quote> getQuotes(@PathVariable("page") int page) {
if(page == 0) {
return Collections.emptyList();
}
return service.getQuotes(page);
}

At this point if you run the process either from IDE or using mvn spring-boot:run command and then hit url http://localhost:8080/quotes/1 then it should return you list of 20 quotes.

Like this we can implement rest as well. Below is complete implementation of our RestController

@RestController
public class QuotesResource {

@Autowired
private QuotesService service;


@GetMapping("/quotes/{page}")
public List<Quote> getQuotes(@PathVariable("page") int page) {
if(page == 0) {
return Collections.emptyList();
}
return service.getQuotes(page);
}

@GetMapping("/quotes")
public List<Quote> getQuotes(@RequestParam("topic") String topic
,@RequestParam(value= "page", required = false, defaultValue = "0") int page) {
if(topic == null || topic.trim().length() == 0) {
return getQuotes(1);
}
return service.getQuotes(topic, page);
}

@GetMapping("/topics")
public List<Topic> getTopics() {
return service.getTopics();
}
}

Apply this change and re-run the spring application. Try to hit endpoint using browser or any other REST client (eg:Postman).

What’s Next:

I created this service in order to create an application which shows quotes to user. Its nice to show relevant images with quotes. Pexels provides API for fetching royalty free images on any topic. We can use this to create an endpoint which will provide images to our end user. In Next post we will create PexelService to consume API provided by Pexels.com using a very sophisticated library provided by Netflix named feign client.

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

Creating REST API in Spring boot – Part3

Rest controller provides end point which will be consumed by end user. For creating a rest controller in spring boot we simply need to annotate the class with annotation @RestController.

As of now we will define below endpoints

  1. /quotes/{page} – to fetch quotes page by page
  2. /quotes?topic={topic} -> to fetch quotes by topic or tag
  3. /topics – to fetch all available topics and its sub topics

Create a class Named QuoteResource and annotate it with @RestController. Define above mentioned three methods in order to provide endpoints


@RestController
public class QuotesResource {

@GetMapping("/quotes/{page}")
public List<Quote> getQuotes(@PathVariable("page") int page) {
return null;
}

@GetMapping("/quotes")
public List<Quote> getQuotes(@RequestParam("topic") String topic
, @RequestParam(value = "page", required = false, defaultValue = "0") int page) {
return null;
}

@GetMapping("/topics")
public List<Topic> getTopics() {
return null;
}

}

@PathVariable : fetches values from URL defined in GetMapping or any other mapping provided. If user hits url /quotes/2 then first method getQuotes will be called and 2 will be passed as param page

@RequestParam: Request param fetches values from Request parameters. In case of GET request request params fetches values from query strings, in case of POST or PUT etc it fetches values from request body as well. Incase a param is optional then we have to define as default value, like we did for page in second getQuotes method

Now we just created a Controller and we have created our backend DB QuoteDB in last post. All we need a communicator or connector which fetches values from DB and provide to controller. We call this piece Service.

What is Service:

You can consider DB as source of data which doesn’t know what it is. It just consider it as piece of data. Controller knows how to present the data to end user. The service layer contains all the business logic and use that to convert raw data received from DB to some useful form. This architecture keeps one responsibility for each component which is easy to manage and test.

Please note: Service layer is supposed to be purely functional. It should never save any state it just contains functions which may or may not take any input and perform particular operation and may or may not return result.

In next post we will create the service layer

Creating REST API in spring boot – Part2

We are done with copying necessaries dependencies and basic spring boot project. As described earlier will be using an in memory database of quotes for serving requests. We have already got the list of quotes and category in form of json files. Its Time to load them into memory.

Let’s understand the structure of Quote and Category first

Quote:

JSON:

{
"quote": "You can observe a lot just by watching.",
"author": "Yogi Berra",
"tags": [

]
}

Each quote will have below properties:

quote: text of the quote.

author: author of the quote

tags: list of tags associated with the quote

Let’s create a POJO class for quote

public class Quote {
private String quote;
private String author;
private List<String> tags;
private int id;
//Getters Setters
}

Category:

JSON:

{
"name":"animal-love",
"imagePath":"https://s3.amazonaws.com/vachan/animal-love.jpg",
"tags":["animals","humanity",""]
}

Each Category will have below properties

name: name of the category

imagePath: path of the image for category or topic

tags: these are sub categories. If some one looks quotes for a particular category the quote will be searched for category and its sub-categories

Now Let’s create a POJO class for Category as well. But we will name it as topic

public class Topic {
private String name;
private String imagePath;
private List<String> tags;
//Getters and Setters
}

Now we are done with models for quotes now let’s create a class to load quotes and serve it to users

Below is functionality provided by this class

  1. It will be a singleton class, hence there will be a single static method which will return instance of QuoteDB
  2. getQuote(): to return all available quotes
  3. getAddedTags() to retuern all available tags for the quotes
  4. getTopics() to return all available Topics or categories
  5. getQuotesFromTopic() to return quotes for a topic in paginated way
  6. getQuote() overloaded method to fetch quotes in paginated way

Create a class name QuoteDB and add below code

public class QuoteDB {
private static QuoteDB instance; // static and singleton instance
private static List<Quote> quotes; // This will contain list of all quotes
private static List<Topic> topics; //This will contains all topics

private static Map<String, List<Integer>> topicQuoteMapper = new HashMap<>(); //This will contain a mapping of quotes for a tag or sub-category

private static final Logger LOGGER = Logger.getLogger(QuoteDB.class);

private QuoteDB(){} // We won't give access to others for creation of QuoteDB instance

/**
* Populates the QuoteDB and returns instance of it
*
@return
*/
public static QuoteDB getInstance() {
if(instance == null) {
instance = new QuoteDB();
populateQuotes(); // Loads quotes
}
return instance;
}
}

populateQuotes method will populate not just quotes but topics and the mapping of quotes with tag as well

So first of all we need a way to read json files. We have used a nice library GSON for this purpose, and we have already added this as a dependency to our pom.xml

Let’s create method to read quotes and topics

// Will read and return list of quotes
private static List<Quote> readQuotes() {
//Try with resource block will make sure to close the stream after use
try(Reader fileReader = new InputStreamReader(QuoteDB.class.getResourceAsStream("/quotes.json"))) {
//This defines a type in which GSON tries to parse contents from json file
Type quoteListType = new TypeToken<List<Quote>>() {
}.getType();
// Reads and returns list of quotes
return new Gson().fromJson(fileReader, quoteListType);
} catch (IOException x) {
LOGGER.error(x.getMessage(), x);
}
return Collections.emptyList();
}

//will read and return list of topics
private static List<Topic> readTopics() {
try(Reader fileReader = new InputStreamReader(QuoteDB.class.getResourceAsStream("/category.json"))) {
Type quoteListType = new TypeToken<List<Topic>>() {
}.getType();
return new Gson().fromJson(fileReader, quoteListType);
} catch (IOException x) {
LOGGER.error(x.getMessage(), x);
}
return Collections.emptyList();
}

So both the functions works in the same way. So may refactor them to have a single method with parameters. But I leave it to you.

Next in the line is the method which will map quotes with topic.

The logic is pretty simple we will have a map with key as tag and value as list of index of quote. We will iterate through list of quotes which was read using readQuotes method and again will iterate over its tag. If map already has this tag as key then we add current quote’s index to the list (value of the map for this tag) otherwise we will create a list of integer and add current quote’s index into it and will put current tag as key and this list as value in the map. Here goes the method

private static Map<String, List<Integer>>  mapQuotesWithTopics(List<Quote> quotes) {
//If quote is null return an empty map
if(quotes == null)
return Collections.emptyMap();
//Creates a map. its key will be tag and value list of index of quotes
Map<String, List<Integer>> topicQuoteMapper = new HashMap<>();
// We will iterate through quote's list
for (int i = 0; i < quotes.size(); i++) {
Quote quote = quotes.get(i);
// Iterate through all tags for this quote
for(String tag : quote.getTags()) {
if(topicQuoteMapper.containsKey(tag.toLowerCase())) {
//If map already contains this tag simply add current quote into the list of quotes for this tag
topicQuoteMapper.get(tag.toLowerCase()).add(i);
} else {
//If not, create a list of integer
List<Integer> indexes = new ArrayList<>();
//Add index of current quote into it
indexes.add(i);
//put them into map
topicQuoteMapper.put(tag.toLowerCase(), indexes);
}
}
}
// Return the map
return topicQuoteMapper;
}

Now we have all pieces for populating our DB. Let’s join them to populate the DB. create a method populateQuote which was called from getInstance method

private static void populateQuotes() {
// populates list of quote
quotes = readQuotes();
// assign an index/id to the quote
for (int i = 0; i < quotes.size(); i++) {
quotes.get(i).setId(i);
}
//populates list of topics
topics = readTopics();
LOGGER.debug("Quotes are loaded");
LOGGER.debug("Indexing quotes");
// maps list of quotes's index with tag
topicQuoteMapper = mapQuotesWithTopics(quotes);
LOGGER.debug("quotes are indexed");
}

Now we are done with populating quotes. Let’s create public methods to expose its services to outer world

/**
* Returns all quotes
*
@return
*/
public List<Quote> getQuotes() {
return quotes;
}

/**
* returns all tags
*
@return
*/
public List<String> getAddedTags() {
return new ArrayList(topicQuoteMapper.keySet());
}

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

We further need to provide mechanism to fetch quotes by pagination or for a tag

For returning quotes in pages we will take an offset which will say from where to start and count which will say how many quotes is required. We will return quotes either equal or less then count. Here goes the method

public List<Quote> getQuotes(int offset, int count) {
if(offset <0 || count < 1)
throw new IllegalArgumentException("Offset can't be less than 0 and Max item cant be less than 1");
//Create a sub list
List<Quote> subQuotes = new ArrayList<>();

//if offset stays beyond size of the quote's list then return empty list
if(quotes.size() < offset) {
return subQuotes;
}
//iterate the list from offset till given number of count and add quotes to sub list
for (int i = offset; i < count + offset; i++) {
//break if i goes beyond quote's list
if(quotes.size() <= i)
break;
subQuotes.add(quotes.get(i));
}
//return populated list
return subQuotes;
}

You can also use List..subList(int fromIndex, int toIndex); instead of looping through list’s index. I leave it to you

The next in the line is method for fetching quote for a tag.

Since we have already created a map which maps tags with list of quote’s index it won’t be too difficult

public List<Quote> getQuotesFromTopic(String tag, int offset, int maxItem) {

if(Strings.isNullOrEmpty(tag)) {
throw new IllegalArgumentException("Topic can't be null");
}
if(offset <0 || maxItem < 1)
throw new IllegalArgumentException("Offset can't be less than 0 and Max item cant be less than 1");
//Returns list of quote's index for given tag
List<Integer> indexes = topicQuoteMapper.get(tag.toLowerCase());

//if no list found then return an empty list
if(indexes == null)
return Collections.emptyList();

//Create a list of quote
List<Quote> mappedQuotes = new ArrayList<>();
// iterate through indexes and add corresponding quote to the new list
for(Integer index : indexes) {
if(mappedQuotes.size() <= maxItem)
mappedQuotes.add(quotes.get(index));
else
break
;
}
// return the list
return mappedQuotes;
}

This completes our QuoteDB. This class will serve as a backend of our app and it needs to be populated before user can consume our api. Hence we have to populate it just after spring app boots.

In your SpringApplication class (Should be named as <Your App name choosen in initializer>Application) call method QuoteDB.getInstance()

Here goes my Application class

@SpringBootApplication
@EnableFeignClients(basePackages = {"com.kgcorner.vachan.services"})
public class VachanApplication {

public static void main(String[] args) {
SpringApplication.run(VachanApplication.class, args);
QuoteDB.getInstance(); // We won't be needing returned instance just now but it will populate our backend
}

}

Why getInstance() for populating data:

I agree the name suggest that it only returns the instance and not populate it. Its better to extract and the population of data into some init method and let this method return only instance. I leave it to you.

In next part we will create our REST controllers which will be consumed by end users for accessing our contents.

Creating REST API in spring boot – Part1

In part1 of the series we will talk about setting up the spring boot application. You may consider this post as Hello world of Spring boot.

Spring boot reduces a lot of boiler plate codes necessary for your web application and it’s pretty easy to make a Micro service.

Visit Spring boot initializer to create and download a bare-bone application with required dependencies

We need to select Maven (you may choose gradle as well). select latest stable version of Spring boot.

Enter a group and artifact id.

Leave the dependencies section as we will add it manually and click on generate project.

This should download a zip file which will contain a spring boot project. Open it in your IDE and edit pom file to have below dependencies

<dependency>
<!-- Actuator provides various monitoring services for your application -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>

<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
<!-- below dependencies are added for testing and details will be explained in related posts -->
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>2.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-reflect</artifactId>
<version>2.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock</artifactId>
<version>2.14.0</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>2.0.0</version>
<scope>test</scope>
</dependency>

Complete pom file is available here

Download Category.JSON and Quotes.JSON and paste it to directory src//main/resources. These files contains static data for available categories of Quotes and Quotes itself

In next post we will read these json file to create a list of categories and quotes and expose API functions to access them.

Creating REST API in spring boot

This is a series of posts which will describe how to create a fully functional REST API using Spring boot.

The application involves various use case like

  1. Consuming external rest service using fiegn client
  2. Automated Testing using Spring boot and Cucumber
  3. Code coverage using JACOCO
  4. Sonar for checking coding standard
  5. maven-release-plugin

So before diving deep into details of the codes of the application let’s take a moment to understand what this REST api provides.

It provides services to fetch Quotes based on topics or in general. It also provides services for fetching images from Pexel for given tags.

As a Database this service loads a JSON file which contains huge number of quotes.

Below is architecture of the application

Complete source code of the application is available on github

So let’s start