I'm implementing a client feign with a hystrix fallback; My problem is that the fallback class calls an API that uses some different data from the clientFeign.
So, my question is: is there a way to pass some additional parameters to my feign, so it can be used just by the fallback class?
#FeignClient(name = "${feign.inventory.name}", url = "${feign.inventory.url:}", fallbackFactory = StockFallback.class)
public interface StockClient {
#RequestMapping(method = GET, value = "/{sku}/{groupId}", consumes = APPLICATION_JSON_VALUE,
produces = APPLICATION_JSON_VALUE)
List<ItemStock> getStockSkuAndInventoryGroup(#PathVariable("sku") final String sku,
#PathVariable("groupId") final String groupId);
}
As spencergibb pointted there is no possibilities of passing an adittional parameter to use in a histrix feign fall back.
So we developed anew end-point which uses the same data as the original, so that the fallback take on clearly and transparent.
Related
I'm migrating an application from NancyFx to Kestrel in ASP.NET Core 6.
In Nancy, you could specify the Accept value in the URI. For example, these Uris:
http://localhost:5000/my/resource.json
http://localhost:5000/my/resource.protobuf
http://localhost:5000/my/resource.xml
Would be the equivalent of setting the Accepts header to application/json, application/protobuf or application/xml respectively.
Does this exist in Kestrel? I remember finding one example, long ago, of regex-ing the route and doing it somewhat manually. But
I can't find that post again, and
If I have to do that, I'm not sure I want to :)
Is there a way to configure this behavior in ASP.NET Core 6?
The object returned from my handler in the controller is already capable of being serialized to json/xml/whatever. I just need to check the URI to set the content-type of the response so the correct formatter will be invoked.
At the moment, I have a client that will speak to both Nancy and Kestrel and it was written to use the URI to get the type. I'm fine to rewrite/update the client so it will use the Accept header. But getting the URI method to work will make the initial integration easier and a refactor to use the headers can come next.
I created a very simple middleware that reads the accept value from the query string and sets the Accept header to the request:
public class AcceptHeaderFromQueryString
{
private readonly RequestDelegate _next;
public AcceptHeaderFromQueryString(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
var accept = context.Request.Query["accept"];
if (!string.IsNullOrEmpty(accept))
{
context.Request.Headers.Accept = accept;
}
await _next(context);
}
}
Register the middleware:
app.UseMiddleware<AcceptHeaderFromQueryString>();
I added [Produces(MediaTypeNames.Application.Json, MediaTypeNames.Application.Xml)] attribute to my api controller action (this step is not required):
[HttpGet]
[Produces(MediaTypeNames.Application.Json, MediaTypeNames.Application.Xml)]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
Finally I added support for xml serialization in Program.cs:
builder.Services.AddControllers()
.AddXmlDataContractSerializerFormatters();
Then I tried these urls and they both gave appropriate response:
https://localhost:7258/weatherforecast?accept=application/json
https://localhost:7258/weatherforecast?accept=application/xml
You possibly want the [Consumes] attribute. This allows you to specify a controller action that only gets called from a route of the specified content type.
Obviously this is not using the Accepts header but the content type of the request.
I was instructed to create webservices ( with Spring-Boot ). My colleague gave me the url of the webservice and it looks like this : http://172.20.40.4:8080/Oxalys_WS/stock/ITM=1559
In general we create a RestController with the url :
#RestController
#RequestMapping("stock")
public class StockController {
#Autowired
private StockService stockService;
#GetMapping(value = "/{code}", produces = "application/json")
public JsonModel getByCode(#PathVariable String code) {
JsonModel jsonModel = new JsonModel();
final Map<String, Object> data = new HashMap<>();
List<Stock> stock = stockService.getByCode(code);
data.put("stock", stock);
data.put("stockTotal", stockService.getTotal(code));
jsonModel.setDatas(data);
return jsonModel;
}
}
So is it normal to create a Restful Spring-Boot webservice with a parameter in the url ?
Spring provides parameter in two standard way.
Query Param : http://172.20.40.4:8080/Oxalys_WS/stock?ITM=1559
Path Variable : http://172.20.40.4:8080/Oxalys_WS/stock/1559
Query Param :- It is a typical old way to pass some value as QueryParam with using of some variable starts with ?(Question Mark) and value is assigned using =(equals).
PathVariable :- this is a newer pattern introduce for REST-api Services. URL must be structured such in a way that this should not look too messy if multiple parameters need to pass within a URL.
For more info Navigate this link
Yes, you can have the one in your URL
When you are required to have the path variable, you can give in the Request URL
When i send a POST request using netflix client , the json properties are blank when it hits the service consumer.
Below is my interface
#FeignClient(name = "NLPService", configuration = FooConfiguration.class )
public interface NLPServiceConsumer extends TempInterface {
}
public interface TempInterface {
#RequestMapping("/greeting")
String greeting();
#RequestMapping(method = RequestMethod.POST,value="/nlp",
consumes="application/json",produces="application/json")
NLPResponse identifyTags(NLPInputToBeTransformed nlpInputToBeTransformed);
#RequestMapping(method = RequestMethod.GET,value="/nlpGetMethod",
produces="application/json")
NLPResponse identifyTagsTest();
}
Method identifyTagsTest works and I am able to successfully get the response .
This method is a GET method with no input
When I try a POST method , passing a object as parameter , at the end point service implementation , the object attributes are null .
Has anybody faced such issue ? Is there any mistake in my configuration ?
The problem was not at the feign client. It was at the service implementation
Spent almost a day on this issue .
The RestController also has to specify #RequestBody ( apart from the shared interface )
can #FeignClient extend - and #RestController implement - a common, fully-annotated Interface?
I have API like this-
/objectname/name
/objectname/collection/id
Both API's are indirectly related.
Problem occurs when calling first API with name value as "A/B Type". So rest controller actually calling second API rather first (/objectname/A/B Type) because forward slash. How to deal with this situation.
As a side note I am encoding the parameters values.
I developed the restful services using SpringBoot and RestTemplate.
The conflict comes by specifying the name directly in the resource path and passed to the function as a #PathVariable.
Your code looks something like this:
#RequestMapping(value = "objectname/{name}", method = RequestMethod.GET)
public String yourMethodName(#PathVariable String name){
return name;
}
What I would recommend in order to avoid this kind of conflict is (if you're allowed to modify the #RestController or #RepositoryRestResource layers) to pass the value of the object in a #RequestParam
For instance:
#RequestMapping(value = "/objectname", method = RequestMethod.GET)
public String yourMethodName(#RequestParam(name = "name", required = true) String name){
return name;
}
That said, When you are constructing your the request using RestTemplate then you should url encode your name (A%2FB%20Testing) and construct the following url:
http://localhost:8080/objectname?name=A%2FB%20Testing
I tested this locally and worked alright for me.
I'm using spring-ws-core to build a SOAP client. For this I'm extending WebServiceGatewaySupport to make the service calls.
public class WeatherClient extends WebServiceGatewaySupport {
...
public WeatherResponse getCityForecastByZip(String zipCode) {
GetCityForecastByZIP request = new GetCityForecastByZIP();
request.setZIP(zipCode);
GetCityForecastByZIPResponse response = (GetCityForecastByZIPResponse) this.getWebServiceTemplate().marshalSendAndReceive(request,
new SoapActionCallback("http://ws.cdyne.com/WeatherWS/GetCityForecastByZIP"));
return response;
}
...
}
Spring configuration is pretty straightforward
#Configuration
public class WebServicesConfiguration {
private static final String WEATHER_SERVICE_DEFAULT_URI = "...";
#Bean(name = "servicesMarshaller")
public Jaxb2Marshaller servicesMarshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("some.package");
return marshaller;
}
#Bean
public WeatherClient weatherService(#Qualifier("servicesMarshaller") Jaxb2Marshaller marshaller) {
WeatherClient client = new WeatherClient(WEATHER_SERVICE_DEFAULT_URI);
client.setMarshaller(marshaller);
client.setUnmarshaller(marshaller);
return client;
}
}
This works just fine for a single web service. Now, suppose that I have many similar web services, but each one has it's own .wsdl specification and URI. I know that I can make a service call through the spring WebServiceTemplate and specify the URI to use. So my idea was to use a single WebServiceGatewaySupport to handle all the calls to the different services. In each call, I would pass the soap action, the corresponding request, if any, and the web service URL. My application is suppose to run in a multi-threaded environment.
Is this a good practice to use a single WebServiceGatewaySupport to handle concurrent calls to different URIs?
Looking to the WebServiceGatewaySupport source code, the short asnwer: yes, it is OK to use it for different URLs, as well as the underlying WebServiceTemplate is thread-safe.
Your implementation will be thread-safe too, if you don't save some state between requests.