In Step 2 we Autowired RestTemplate with Load balancing with Discovery client capabilities.
Here we still has an issue, although we have configured service-discovery, load balancing
Can we make it more abstract
Feign Client is the solution
Let's look at the needs and configurations
1. Add Feign Client dependency.
1.1 Open feign dependency, additionally Web and also discovery-client etc as needed.
2. Create an interface to configure url and method
3. Autowire the object of the interface and call the method. Here we do it in the Controller itself for time being. Better to do it in the service layer @Service
Code Blocks and Configurations
POM
<!-- Feign client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
Create Interface
package com.example.rest_client_with_feign.client;
import com.example.rest_client_with_feign.model.Greet;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
/**
* 1. Define interface with suitable name
* 2. Declare method as needed
*/
@FeignClient("greet-service")
public interface GreetClient {
@GetMapping("/greet")
public Greet greet();
}
Controller with Feign Client Interface Autowired
package com.example.rest_client_with_feign.controller;
import com.example.rest_client_with_feign.client.GreetClient;
import com.example.rest_client_with_feign.model.Greet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
public class GreetClientController {
//Step 1
// private RestTemplate restTemplate = new RestTemplate();
//Ste 2 - 1. define bean in main class , add @LoadBalanced
// @Autowired
// private RestTemplate restTemplate;
//Step-3
@Autowired
GreetClient greetClient;
/*
@RequestMapping("/greet-call")
Greet greet() {
//Phase 1 - without Discovery/Eureka client
// Greet greet = restTemplate.getForObject("http://localhost:8090/greet", Greet.class);
//Step 2
//With Discovery client - Now we can use service name - and with other option available via eureka server
// you need to configure DiscoveryClient - else cannot find hte hostname "greet-service" which is registered inEureka server
Greet greet = restTemplate.getForObject("http://greet-service/greet", Greet.class);
return greet;
}
*/
/**
* Step 3 :Using Feign Client
* @return
*/
@RequestMapping("/greet-call")
Greet greet() {
//simple mthod call - compare with above step 2
return greetClient.greet();
}
}
Application properties
spring.application.name=rest-client-with-feign
#spring.application.name=rest-client
server.port=8095
#phase 2 - add eureka
eureka.client.serviceUrl.defaultZone= http://localhost:8761/eureka/
you can test with
1. make sure greet-service , eureka server up and running. Eureka is optional
2. http://localhost:8095/greet-call
This is a simple Summary to understand
----------------------------------------------------------------------------------------------------------
For more information you can refer below
1. Create a Spring Boot Project
Use Spring Initializr with these dependencies:
Spring Web
OpenFeign
Lombok (optional for boilerplate reduction)
2. Enable Feign Clients
Add @EnableFeignClients
to your main application class:
@SpringBootApplication @EnableFeignClients public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
3. Define Feign Client Interface
Create an interface annotated with @FeignClient
:
import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @FeignClient(name = "user-service", url = "https://jsonplaceholder.typicode.com") public interface UserClient { @GetMapping("/users/{id}") UserResponse getUserById(@PathVariable("id") Long id); }
4. Create DTO (Data Transfer Object)
Define the response model (JSON structure must match the API response):
import lombok.Data; @Data public class UserResponse { private Long id; private String name; private String email; private String phone; }
5. Use Feign Client in a Service
Inject the Feign client and use it:
import org.springframework.stereotype.Service; @Service public class UserService { private final UserClient userClient; public UserService(UserClient userClient) { this.userClient = userClient; } public UserResponse getUser(Long id) { return userClient.getUserById(id); } }
6. Create a REST Controller
Expose an endpoint to trigger the Feign client:
import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/api/users") public class UserController { private final UserService userService; public UserController(UserService userService) { this.userService = userService; } @GetMapping("/{id}") public UserResponse getUser(@PathVariable Long id) { return userService.getUser(id); } }
7. Configure Application Properties
Add this to application.properties
:
# Enable Feign logging (optional) logging.level.org.springframework.cloud.openfeign=DEBUG feign.client.config.default.loggerLevel=full # Timeout configuration (example) feign.client.config.default.connectTimeout=5000 feign.client.config.default.readTimeout=5000
8. Test the Application
Start the Spring Boot app
Access:
http://localhost:8080/api/users/1
Expected JSON response:
{ "id": 1, "name": "Leanne Graham", "email": "Sincere@april.biz", "phone": "1-770-736-8031 x56442" }
Key Configuration Options:
Multiple Clients:
@FeignClient(name = "payment-service", url = "${payment.api.url}")
Error Handling:
@FeignClient(name = "user-service", configuration = CustomErrorDecoder.class)
Request Interceptors (for headers/auth):
@Bean public RequestInterceptor requestInterceptor() { return template -> template.header("Authorization", "Bearer TOKEN"); }
Troubleshooting Tips:
Ensure
@EnableFeignClients
is presentVerify the base URL matches the target service
Check DTO fields match the API response exactly
Use
@RequestMapping
instead of@GetMapping
for complex requestsAdd
@EnableAutoConfiguration
if using older Spring versions
No comments:
Post a Comment