Feign Client ignoring request params - spring-boot

I created Feign Client:
#FeignClient(name = "yandex",url="${yandex.ribbon.listOfServers}")
public interface YandexMapsRestApiServiceClient {
#RequestMapping(method = RequestMethod.GET, value = "{geoParam}")
String getCountryInfo(#Param("geoParam") String geoParam);
}
In controller I have been wrote:
#Autowired
private YandexMapsRestApiServiceClient client;
#RequestMapping(value = "/", method = RequestMethod.GET)
public String test() {
return client.getCountryInfo("Moscow");
}
My Applicaton.yml look this:
yandex:
ribbon:
listOfServers: https://geocode-maps.yandex.ru/1.x/?format=json&geocode=
ConnectTimeout: 20000
ReadTimeout: 20000
IsSecure: true
hystrix.command.default.execution:
timeout.enabled: true
isolation.thread.timeoutInMilliseconds: 50000
When I try to get some result, in return I get 404 error:
feign.FeignException: status 404 reading YandexMapsRestApiServiceClient#getCountryInfo(String); content:
In this case, I see in the debugger that he feign not set my geoParam:
Why does this happen and how to solve this problem?

As Musaddique has stated, you are mixing Feign and Spring annotations. When using Spring Cloud Feign(OpenFeign), you must use the Spring annotation RequestParam. Feign annotations will not be processed.
Update
To achieve what you are looking for, you will need to change your configuration. The of url should be a url or service name only. Using query string or other extensions to the url will have unexpected results.
Move the path information to the RequestMapping annotation and specify the query parameter there.
#FeignClient(name = "yandex", url="${yandex.ribbon.listOfServers}")
public interface YandexMapsRestApiServiceClient {
#RequestMapping(method = RequestMethod.GET, value = "/1.x?format=json&geocode={geoParam}")
String getCountryInfo(#RequestParam("geoParam") String geoParam);
}
Where your ribbon configuration looks like this:
yandex:
ribbon:
listOfServers: "https://geocode-maps.yandex.ru"
ConnectTimeout: 20000
ReadTimeout: 20000
IsSecure: true
Now, using your example of client.getCountryInfo("moscow") will result in the final url of https://geocode-maps.yandex.ru/1.x?format=json&geocode=moscow.

Related

Is there support for multiple feign.Client beans within Spring

Some context
The project is a spring boot application (v 2.3.12) using spring-cloud-openfeign-core (v 2.2.8) to make REST requests.
The service has 2 clients
one that needs to make REST requests using a proxy
one that needs to make REST request without a proxy
I'm unable to get both client to work simultaneously, i.e. have requests work for both proxied and non-proxied resources.
Is it possible to use different configuration files to support this, I have tried something like this
Configuration class X
#bean
public Client client1() {
return new Client.Default(null, null);
}
Configuration class Y
#bean
public Client client2() {
return new Client.Proxied(null, null,
new Proxy(Proxy.Type.HTTP, new InetSocketAddress("10.0.0.1", 8080)));
}
Feign interface code looks something like this
#Service
#FeignClient(name = "service1", url = "internal-url", configuration = X.class)
#Headers("Content-Type: application/json")
public interface serviceClient1 {
#PostMapping(value = "/v1/path}")
Response1 update(#RequestBody Request1 request1);
}
#Service
#FeignClient(name = "service2", url = "external-url", configuration = Y.class)
#Headers("Content-Type: application/json")
public interface serviceClient2 {
#PostMapping(value = "/v1/path}")
Response2 update(#RequestBody Request2 request2);
}
It seems only one of the client beans is used when making requests.

No http client metrics for non 200 response codes in Quarkus Micrometer

I have the following Quarkus Rest client code (based on this doc https://quarkus.io/guides/rest-client)
#RegisterRestClient(baseUri = "https://pesho3.free.beeceptor.com")
interface TokenService {
#POST
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
#Produces(MediaType.APPLICATION_JSON)
#ClientHeaderParam(
name = "Authorization",
value = ["Basic asdasd"]
)
fun getToken(
#FormParam("grant_type") grantType: String = "client_credentials",
#FormParam("scope") scope: String = "IIG-HIP-NP/Read"
): JSONObject
}
When I call my getToken() method and get http 200 I get automatically generated metrics in localhost:8080/q/metrics (as stated in this doc https://quarkus.io/guides/micrometer#review-automatically-generated-metrics)
e.g
http_client_requests_seconds_count{clientName="pesho3.free.beeceptor.com",method="POST",outcome="SUCCESS",status="200",uri="root",} 2.0
http_client_requests_seconds_sum{clientName="pesho3.free.beeceptor.com",method="POST",outcome="SUCCESS",status="200",uri="root",} 1.116203
I don't get any metrics for non 200 codes.. How can I expose them ?
I found the solution.. Its this property (not mentioned in Quarkus doc)
microprofile.rest.client.disable.default.mapper=true
The answer was in this doc:
https://download.eclipse.org/microprofile/microprofile-rest-client-1.3/microprofile-rest-client-1.3.html#_default_responseexceptionmapper

Required request part 'file' is not present in Spring Boot

I checked all of the simular posts and still couldnt find the solution.
Problem is Required request part 'file' is not present in test class.
I want to upload a file and save it to the database. Here is my rest controller #RestController:
#PostMapping(value = "/upload")
public ResponseEntity<LogoDto> uploadLogo(#RequestParam("file") MultipartFile multipartFile) {
return ResponseEntity.ok(logoService.createLogo(multipartFile));
}
and my test class:
#Test
public void createLogo2() throws Exception {
String toJsonLogoDto = new Gson().toJson(logoDto);
MockMultipartFile file = new MockMultipartFile("path", "url", MediaType.APPLICATION_JSON_VALUE, image);
LogoDto response = LogoDataTest.validLogoDto();
Mockito.when(logoServiceMock.createLogo(Mockito.any(MultipartFile.class))).thenReturn(response);
mockMvc.perform(MockMvcRequestBuilders.multipart("/brand-icon/upload")
.file(file)
.content(MediaType.APPLICATION_JSON_VALUE)
.contentType(MediaType.APPLICATION_JSON_VALUE)
.characterEncoding(CharEncoding.UTF_8))
.andDo(MockMvcResultHandlers.print())
.andExpect(MockMvcResultMatchers.status().isOk());
}
and my application.yml looks like this:
spring:
servlet:
multipart:
enabled: true
max-file-size: 2MB
max-request-size: 10MB
I tried to add consumes in my #PostMapping;
try to set literally every MediaTypes.. still get an error.
I appreciate all of your answer.
issue is in declaration of MockMultipartFile, first parameter should match controller #RequestParam param. So, in your case, should be:
MockMultipartFile file = new MockMultipartFile("file", "url", MediaType.APPLICATION_JSON_VALUE, image);
Also, I recommend to update your controller method to the following one:
#PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<LogoDto> uploadLogo(#RequestPart("file") MultipartFile multipartFile) {
...
}

swagger annotation content-type not set

I have this spring rest controller:
#RestController
#RequestMapping("/communications")
class CommunicationController(private val service: CommunicationService) {
#ApiOperation(
produces = APPLICATION_JSON_VALUE,
consumes = APPLICATION_JSON_VALUE
)
#GetMapping(
consumes = [APPLICATION_JSON_VALUE],
produces = [APPLICATION_JSON_VALUE]
)
fun findAll(
criterias: CommunicationCriterias,
page: Pageable
): List<CommunicationDTO> = service.findCommunications(criterias, page)
}
When I test this endpoint via the swagger-ui (springfox) interface, i got a 415: content type invalid error. It seems that content-type: application/json is not set in the header.
What is missing ?
There is nothing to consume in HTTP GET request. I think you should remove the consumes from #GetMapping and #ApiOperation.

spring rest app, can't get data from PUT

I have two methods in controller, this is handler request from client. I can't get request body of PUT. For send request i use Advanced Rest Client in Chrome.
#RequestMapping(value = "/addPupil", method = RequestMethod.POST)
public void addPupil(Pupil pupil){
System.out.println(pupil.toString());
}
Result in Advanced Rest Client:
Status 200 OK Response does not contain any data.
stdout:
Pupil{address='is address', level='is level', group='is group', last='is last', name='is name'}
But problem with this method, i can't get pupil object!
#RequestMapping(value = "/changePupil/{id}", method = RequestMethod.PUT)
public void changePupil(#PathVariable("id") Long id, Pupil pupil){
System.out.println("id: "+id);
System.out.println(pupil.toString());
}
Result in Advanced Rest Client:
Status 200 OK Response does not contain any data.
stdout:
id: 2
Pupil{address='null', level='null', group='null', last='null', name='null'}
you should use #RequestBody
#RequestMapping(value = "/changePupil/{id}", method = RequestMethod.PUT)
public void changePupil(#PathVariable("id") Long id,#RequestBody Pupil pupil){
System.out.println("id: "+id);
System.out.println(pupil.toString());
}
Take an advantage of #RestController on your controller class instead of #Controller and specify the MediaType that your rest method consuming and you may have to register appropriate HttpMessageConverter too.
Ref: How to configure MappingJacksonHttpMessageConverter while using spring annotation-based configuration?

Resources