I have a JAX-RS #POST endpoint whose input data has to be #Valid:
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response myEndpoint(#javax.validation.Valid MyInputData input) { /*...*/ }
With MyInputData class annotated with many constraints:
#lombok.Data
public class InputData {
#Size(min = 1, max = 3)
private String someString;
/* ... */
}
Beyond that I have an ExceptionMapper<ConstraintViolationException> that transform the Exception into a Collection<String> (basically every single ConstraintViolation transformed to String using its getMesssage() method), then returns a Response.status(Status.BAD_REQUEST).entity(list).build().
Everything is working nicely. Fed an invalid input and I get back a HTTP 400 with a nice array of constraint violations in json format.
So far, so good...
BUT... the messages are in server's locale. Even if HTTP post sends a Accept-language header (and it is correctly detected when getting HttpServletRequest::getLocale).
By the time the ExceptionMapper gets hold of ConstraintViolation every message has already been interpolated, so no chance set the client locale.
Since the validation runs even before the JAX-RS resource (indeed, the JAX-RS resource isn't even called in case of invalid input), this locale aware message interpolator must be configured somewhere else.
Where? Is there already a MessageInterpolator implementation whose operation takes the HttpServletRequest locale into account?
Related
I need access to RequestBody inside OnActionExecuting or OnActionExecuted filter, but I can not found concrete example how to use PipeReader to read full request body stream and return stream position to zero (in order to read request parameters by ControllerBase - if I read body OnActionExecuting or firstly return position to zero if I read in OnActionExecuting).
In my attribute Body always empty.
However, API parameters is present.
Or maybe there is another way to receive Request Body in Action Filter for ControllerBase?
From your description, I think you wanna get request body in multiple times in asp.net core. But in asp.net core, the request can not be read once it is consumed. If you want to read the request body multiple times, you need to set:
context.Request.EnableBuffering()
Then to read the body stream you could for example do this:
string bodyContent = new StreamReader(Request.Body).ReadToEnd();
On the safer side, set the Request.Body.Position reset to 0. That way any code later in the request lifecycle will find the request body in the state just like it hasn’t been read yet.
Request.Body.Position = 0;
So you can set this code in either OnActionExecuting or OnActionExecuted method.
public void OnActionExecuting(ActionExecutingContext context)
{
context.HttpContext.Request.EnableBuffering();
string bodyContent = new StreamReader(context.HttpContext.Request.Body).ReadToEnd();
context.HttpContext.Request.Body.Position = 0;
}
But please note that, Model binding happens before action filter, So Model binding will consume request body first and you can not read it in your action filter, You need to custom model binding and Apply the above configuration to it.
I have two POST methods and one DELETE in my resource. They have same path.
I annotated one of POSTs with #DefaultMethod, so when someone doesn't send correct Accept header, correct method will be selected. But this causes that when DELETE is called, cxf selects POST instead of correct delete method. Is there any workaround for this?
CXF version: 3.1.17
#DefaultMethod
#POST
#Consumes(MeasurementMediaType.MEASUREMENT_TYPE)
#Produces(MeasurementMediaType.MEASUREMENT_TYPE)
public Response post(MeasurementRepresentation measurementRepresentation, #HeaderParam(value = HttpHeaders.ACCEPT) String acceptHeader) URISyntaxException {
...
}
#POST
#Consumes(MEASUREMENT_COLLECTION_TYPE)
#Produces(MEASUREMENT_COLLECTION_TYPE)
public Response post(MeasurementCollectionRepresentation measurementCollectionRepresentation, #HeaderParam(value = HttpHeaders.ACCEPT) String acceptHeader) {
...
}
#DELETE
public Response delete(
#QueryParam("fragmentType") String fragmentType,
#QueryParam("source") String source,
#QueryParam("dateFrom") DateTime dateFrom,
#QueryParam("dateTo") DateTime dateTo,
#QueryParam("type") String type) {
...
}
java.lang.NullPointerException
at com.cumulocity.measurement.rest.resources.MeasurementCollectionResource.post(MeasurementCollectionResource.java:280)
Two things:
1) DefaultMethod appears not to refer to the default method to select, but the default HTTPMethod. So it's essentially overriding the httpmethod of your call. This is a CXF extension to JAX-RS, so you may be able to ask the CXF team to update the functionality or create a new annotation for your use case.
2) If I understand you correctly, you would like the first method to be called if someone sends the body of {"Hello" : "World"}? Wouldn't you then get errors when trying to construct your MeasurementRepresentation? If they send a bad request, why not let CXF respond with an appropriate HTTP error code?
In my application, I need to call an external endpoint and if it is too slow a fallback is activated.
The following code is an example of how my app looks like:
#FeignClient(name = "${config.name}", url = "${config.url:}", fallback = ExampleFallback.class)
public interface Example {
#RequestMapping(method = RequestMethod.GET, value = "/endpoint", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
MyReturnObject find(#RequestParam("myParam") String myParam);
}
And its fallback implementation:
#Component
public Class ExampleFallback implements Example {
private final FallbackService fallback;
#Autowired
public ExampleFallback(final FallbackService fallback) {
this.fallback = fallback;
}
#Override
public MyReturnObject find(final String myParam) {
return fallback.find(myParam);
}
Also, a configured timeout for circuit breaker:
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 5000
How can I implement an integration test to check if my circuit break is working, i.e, if my endpoint (mocked in that case) is slow or if it returns an error like 4xx or 5xx?
I'm using Spring Boot 1.5.3 with Spring Cloud (Feign + Hystrix)
Note i donot know Feign or Hystrix.
In my opinion it is problematic to implement an automated integrationtest that simulates different implementatondetails of Feign+Hystrix - this implementation detail can change at any time. There are many different types of failure: primary-Endpoint not reachable, illegal data (i.e. receiving a html-errormessage, when exprecting xml data in a special format), disk-full, .....
if you mock an endpoint you make an assumption of implementationdetail of Feign+Hystrix how the endpoint behaves in a errorsituation (i.e. return null, return some specific errorcode, throw an exception of type Xyz....)
i would create only one automated integration test with a real primary-enpoint that has a never reachable url and a mocked-fallback-endpoint where you verify that the processed data comes from the mock.
This automated test assumes that handling of "networkconnection too slow" is the same as "url-notfound" from your app-s point of view.
For all other tests i would create a thin wrapper interface around Feign+Hystrix where you mock Feign+Hystrix. This way you can automatically test for example what happens if you receive 200bytes from primary interface and then get an expetion.
For details about hiding external dependencies see onion-architecture
I am writing unit tests for my application with Spring Data Rest MongoDB. Based on Josh's "Building REST services with Spring" get start guide, I have the following test code:
#Test
public void readSingleAccount() throws Exception {
mockMvc.perform(get("/accounts/"
+ this.account.getId()))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$.id", is(this.account.getId())))
.andExpect(jsonPath("$.email", is(this.account.getEmail())))
.andExpect(jsonPath("$.password", is(this.account.getPassword())));
}
And this test fails on the content type.
Content type expected:<application/json;charset=UTF-8> but was: <application/hal+json>
Expected :application/json;charset=UTF-8
Actual :application/hal+json
I don't see MediaType come with HAL. Is the content type defined in another class?
Had the same Problem when not using tomcat (which is configured to return utf-8 using Spring Boot). The solution is to set the accept header in your GET request so the response gets the correct content type:
private MediaType contentType = new MediaType("application", "hal+json", Charset.forName("UTF-8"));
and in your request, do
#Test
public void readSingleAccount() throws Exception {
mockMvc.perform(get("/accounts/"
+ this.account.getId()).**accept(contentType)**)
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$.id", is(this.account.getId())))
.andExpect(jsonPath("$.email", is(this.account.getEmail())))
.andExpect(jsonPath("$.password", is(this.account.getPassword())));
}
I run a web service where I convert a file from one file format into another. The conversion logic is already functioning but now, I want to query this logic via Jersey. Whenever file upload via Jersey is addressed in tutorials / questions, people describe how to do this using multipart form data. I do however simply want to send and return a single file and skip the overhead of sending multiple parts. (The webservice is triggered by another machine which I control so there is no HTML form involved.)
My question is how would I achieve something like the following:
#POST
#Path("{sessionId"}
#Consumes("image/png")
#Produces("application/pdf")
public Response put(#PathParam("sessionId") String sessionId,
#WhatToPutHere InputStream uploadedFileStream) {
return BusinessLogic.convert(uploadedFile); // returns StreamingOutput - works!
}
How do I get hold of the uploadedFileStream (It should be some annotation, I guess which is of course not #WhatToPutHere). I figured out how to directly return a file via StreamingOutput.
Thanks for any help!
You do not have to put anything in the second param of the function; just leave it un-annoted.
The only thing you have to be carefull is to "name" the resource:
The resource should have an URI like: someSite/someRESTEndPoint/myResourceId so the function should be:
#POST
#Path("{myResourceId}")
#Consumes("image/png")
#Produces("application/pdf")
public Response put(#PathParam("myResourceId") String myResourceId,
InputStream uploadedFileStream) {
return BusinessLogic.convert(uploadedFileStream);
}
If you want to use some kind of SessionID, I'd prefer to use a Header Param... something like:
#POST
#Path("{myResourceId}")
#Consumes("image/png")
#Produces("application/pdf")
public Response put(#HeaderParam("sessionId") String sessionId,
#PathParam("myResourceId") String myResourceId,
InputStream uploadedFileStream) {
return BusinessLogic.convert(uploadedFileStream);
}