Generating Feign clients with Swagger Codegen and Gradle

In the last article, I showed you how to use a custom template for code generation. If you haven’t read the previous parts of the series, make sure you do that before continuing.

About Feign

First of all, I won’t give you a deep intro into Feign as the article is not about that, but rather I’ll give a high-level overview. Feign’s goal is to enable building declarative HTTP clients with lots of customization. Imagine that you want to make an HTTP call from ServiceA to ServiceB. If you are familiar with the Spring world, most probably you’d go with Spring’s RestTemplate . There’s nothing wrong with that, but Feign approaches this problem a bit differently. You just define an interface in ServiceA according to the contract of ServiceB and make some configuration like where the endpoint lies, what are the parameters, headers, etc.

Let’s have a quick example. This can also be found on OpenFeign’s GitHub page.

As you can see, an interface is defined for the API, called GitHub and you can create a client according to that using Feign’s builder API. After you’re done with building, you can invoke the GitHub API via a simple method call.

Additionally, Feign is capable of multiple customization like using Ribbon, Hystrix, special logging or request management and many more.

Feign with Spring Cloud

Feign has it’s custom annotations for defining the APIs and you have to build your clients manually. Spring Cloud has a Feign integration which means that you can have Spring MVC annotations to define the API, like @RequestMapping , @PathVariable , @RequestParam , etc. Also, you don’t need to manually create the clients, you can just annotate the interface with @FeignClient  and add the proper configuration there plus put the @EnableFeignClients  annotation on one of the configuration classes.

This integration with Spring’s ecosystem comes handy as you can use the Feign clients as regular beans. Inject them into a bean and just simply invoke the method you want. Very very useful and clean compared to a RestTemplate  for example.

Generating Feign clients

Now back to Swagger code generation. It’s already a great thing if you can provide a contract for your API for clients but even better if you could prepare an artifact with which the clients can interact with your API. With Spring Cloud, it’s possible to have Feign clients which doesn’t have hardcoded URLs, ports for the services they are working with instead they can use Eureka to resolve the services by name. This is what we’ll use for generating the Feign clients.

Swagger Codegen has 3 libraries for the language spring : spring-boot , spring-cloud , spring-mvc . For generating Feign clients, we’ll use spring-cloud as it’s already prepared for it, we’ll just customize it a bit for Eureka discovery.

Starting from the state where the previous article ended, we have the template  folder in the project which contains the mustache templates for generation. In the libraries  folder, there are 3 sub-directories, each for one of the 3 libraries. As we are going to use the spring-cloud library , let’s remove spring-boot  and spring-mvc .

Okay, now let’s extend the buildscript with generating the Feign client. First of all, we’ll need a new placeholder project next to the other one, call it user-service-feign-client . The updated settings.gradle  looks the following:

Including the Feign client generation in the build process is not that complicated if we’re reusing the existing server-side generator. The build.gradle  is extended with the following

Again, referencing the client project, adding the dependencies which will be used for the client code and setting up the Swagger generator. The important change here is that there is a new setting where we set the used library which is spring-cloud . Also, there is an additional property called title  which will be used in the client template for Eureka discovery.

After executing ./gradlew clean build , there will be an error popping up which describes that there is a compilation failure due to missing classes.

This happens because Swagger’s default template is using OAuth2 for the client generation along with other custom interceptors. Usually I don’t need this so I’ll show you a way how to get rid of this.

Change the client generation in the build.gradle  to this:

There is a new task added, called deleteNonClientRelatedClasses  which is responsible to delete the src/main/java/io  folder where Swagger Codegen puts the configuration classes by default. Now we are left with a single error that the ClientConfiguration  class is not found for the generated Feign clients, but this is expected as we deleted it.

The Feign client template is stored in the apiClient.mustache  file within the spring-cloud  library folder. Let’s open it and delete the unnecessary configuration for the client. The default template is the following:

Now we can remove the import for the ClientConfiguration  class as well as configuration for the @FeignClient  annotation. Also, as only Eureka discovery will be used for the Feign clients, I’ll simply remove the url  configuration as well and end up with this:

It’s a really basic Feign client and the service will be resolved by it’s name, in this case the name of the service should be user-service  in Eureka. This is how the generated code looks like:

After executing again ./gradlew clean build install , this client artifact can be included in any other service to invoke the user-service .

Testing time

Testing it is a bit tricky as we’ll need a Eureka server, we have to enhance the current user-service to register itself to Eureka and create actually another service which will call the user-service via Feign.

Let’s start with adding Eureka support to the user-service. The build.gradle  for the service will now include spring-cloud-eureka  as a dependency and the Application  class will have @EnableDiscoveryClient  annotation on it.

Okay, now check out the Eureka service. It’s basically a simple Spring Boot app with a dependency to eureka-starter  and a bit of configuration. I’ve created a new project called discovery-service with Spring Initializr. The most important thing here is the @EnableEurekaServer  annotation on the Application class and the following bootstrap.yml .

Next up, we’ll need another service where we can trigger the Feign invocation. Imagine a payment-service which will interact with the user-service. It will be a simple Spring Boot app with Eureka client and a very simple controller.

After creating the project, open the build.gradle  and include the generated Feign client. Of course, don’t forget to add mavenLocal()  as a repository.

The Application  class looks the following:

Notice the @EnableFeignClients  annotation which will initiate the Feign client building process. Create a PaymentController  with one method available which will invoke the client.

One last step is missing, to fill up the response from user-service. Go back to the delegate and add some static data to the getUsers  method.

Start the discovery-service first, then the payment-service and the user-service. You can do this from your favorite IDE or by executing ./gradlew clean bootRun  on each of them.

Open up your Postman or any other REST Client and invoke GET http://localhost:8001/payment . If you did everything correctly, you’ll see the following response coming back:

Cool, right? We just used the generated client from the contract to handle interaction between services.

Recap

In this article, we’ve checked how you can generate Feign clients from a Swagger contract. It’s extremely useful when you want to provide not only your API contract, but a ready to be used artifact with which you can invoke the actual API. Also, we’ve created a small test environment to test the generated Feign client and invoke the service which has the Swagger generated API.

The full project is available on GitHub.

Let me know what you think about this part of the series in the comments or on Twitter. Share it, like it, more articles are coming.

Leave a Reply

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