Netflix microservices stack, part 1: Feign

Netflix microservices stack tutorials:
На русском

At my job I was recently tasked with investigating the possibility of separating our monolithic web-application into services (I'm a Java developer BTW). Obviously, we couldn't just break our huge back-end application into a swarm of microservices in reasonable time, that's why the focus of my research lay in gradual transition to service-based architecture. It may sounds hard, but not insurmountable anymore!

Quite surprisingly, during my furious googling(hehe) I found that the giant of cloud-based streaming media services, namely Netflix, has open-sourced its framework of microservice tools.

I managed to learn two things in the course of my investigations: microservice architecture is infinitely scalable and simple and that there's not nearly enough example-backed reading material on the Internet on the subject of using Netflix microservices on Spring Cloud without Eureka (which is responsible for service discovery).

So in these series of blog posts, I'm going to try and enlighten the reader on the subject of Netflix microservice stack, beginning with Feign - the declarative REST client library. Then I'll follow up with the post on the hot topic of adding client-side load balancing with Ribbon (with hard-coded services at first), and hopefully there will even be the third post with dynamic service discovery using Eureka.

Some theory beforehand

Before lunging head-first into a completely new area of expertise, it helps to read up on the subject. I'll share my personal favorite reading list for microservice-related stuff:
Feign is the first stepping stone of implementing microservice architecture with Netflix tools. In the reality of loosely-coupled services, lightweight and simple to debug communication is the key. That is why REST is often the communication of choice, even if sometimes it's not the best choice possible (take a look at this and this for details). That's where we'll use Feign: it will consume the messages from other services and convert them into Java objects.

Practice time!

First of all, let's create a Spring Boot application for our client. That's not strictly necessary, but it makes for easy configuration, and Spring Cloud Feign starter (what's a starter?) that we will use pulls Spring Boot as a dependency anyway.

If "create a spring boot application" doesn't sound straightforward to you, you can follow this tutorial to do it. Don't worry, it's a breeze.

Add feign starter dependency into your pom.xml (<dependencies> section):

Now's the best time to decide what kind of REST API are we going to consume. For the sake of completeness, I'll demonstrate the whole range of CRUD operations in this example. Now, only the last piece of this puzzle is  missing: who is going to provide us with a RESTful service conforming to a given specification? There are free to use websites that do just that: expose a fully-defined REST API for testing purposes. I found at least two services like this: ReqRes and JSONplaceholder:

ReqRes and JSONplaceholder provide a complete REST API to test our Feign app.

Feign uses interfaces annotated with @FeignClient to generate API requests and map responses to Java classes. Let's first compile a list of API calls:

Action HTTP Method URL
(C) Create a user POST https://jsonplaceholder.typicode.com/users
(R) Get a list of users GET https://jsonplaceholder.typicode.com/users
(R) Get one user GET https://jsonplaceholder.typicode.com/users/{id}
(U) Update user details PUT or PATCH https://jsonplaceholder.typicode.com/users/{id}
(D) Delete a user DELETE https://jsonplaceholder.typicode.com/users/{id}

Now we can create model classes and an interface to describe REST API to Feign:
  • Add a dependency for Jackson - JSON (de)serializer. Feint will use it to handle JSON in HTTP requests and responses.
    (Optional) Add Lombok dependency to pom.xml.
    Lombok automatically generates the boilerplate code associated with POJOs (getters, setters, constructors). You can skip this, but you'll have to write getters/setters for your model classes manually.
  • Create model classes in model package under root package.
  • Create Feign client interface in feign package under root package.
  • Create a controller with Feint client invocation, just to make sure it works. Here's what each of those lines do:

    .contract defines what annotations and values are valid on Feign interfaces. Specifically, with SpringMvcContract() we can annotate our client methods with Spring annotation @RequestMapping. Without this you'd get UnsatisfiedDependencyException: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userController': Unsatisfied dependency expressed through field 'userClient';
    .encoder and .decoder will allow Feint client map JSON to Java objects and back,
    .logger and .logLevel will log each request and response to System.error. Convenient for create, update and delete calls where you can't exactly tell if it works or fails silently.,
    .target is pretty much self-explanatory. That's where our application will send its requests and receive responses.

  • Launch your application, go to http://localhost:8080/read.
    Looks like we can connect and get the list of users! You may take a look at the console window in your IDE to see the details of HTTP communications:
That was the absolute minimum you need to know about using Feint with Spring Cloud.

If you'd like to check out how other methods (create, update, delete) work and learn how to exact UserClient to a bean instead of creating it manually in every class where you need it, I'll be glad to continue my rant😊

Imagine a real-world application with at least 50 classes in it. Let's say about 20 of them use our UserClient for authentication. You think writing Feign.build().... in each one of them is painful? Think about change of communication from JSON to XML! That's where the wonderful Spring Beans will save the day. Before we start with checking other CRUD methods, let's turn UserService into a bean:
  • Create a configuration class for Spring context in a new config package under root package.

    Under /src/main/resources create an application.properties file with a single line:
  • UserService can be autowired into any class. The controller class can be rewritten to include other CRUD methods and a simpler autowired UserService:
  • If your application starts now, that means autowiring works its wonders. At last, you can try each method out in your browser:

Thank you for following the guide all the way through. Stay tuned for part two, where we'll add Ribbon load balancing with hard-coded list of services!

As usual, the project can be found here: GitHub

Comments