Webapi CreateErrorResponse throws ArgumentException - asp.net-web-api

I'm trying to call to the extension method CreateErrorResponse with a status code and string.
The problem that the function throws ArgumentException with additional information that the value dose not fall within the expected range.
I tried to send different values of arguments, explicitly cast the arguments and using different overloads.
Code
private HttpResponseException GetItemsException(IEnumerable<Guid> ids, string errorMessage, HttpStatusCode status)
{
HttpResponseMessage error = Request.CreateErrorResponse(status, errorMessage);
error.Headers.Add("ids", ids.Select(id => id.ToString()));
return new HttpResponseException(error);
}

Related

How is HttpServletResponse entangled with the fetch API when making a GET request for a BLOB?

Using Spring Boot, I am trying to implement a REST controller, which can handle a GET request asking to return a BLOB object from my database.
Googling around a little bit, and putting pieces together, I have created the following code snippet:
#GetMapping("student/pic/studentId")
public void getProfilePicture(#PathVariable Long studentId, HttpServletResponse response) throws IOException {
Optional<ProfilePicture> profilePicture;
profilePicture = profilePictureService.getProfilePictureByStudentId(studentId);
if (profilePicture.isPresent()) {
ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(profilePicture.get().getPicture());
outputStream.close();
}
}
I am sending the GET request using VanillaJS and the fetch-API:
async function downloadPicture(profilePic, studentId) {
const url = "http://localhost:8080/student/pic/" + studentId;
const response = await fetch(url);
const responseBlob = await response.blob();
if (responseBlob.size > 0) {
profilePic.src = URL.createObjectURL(responseBlob);
}
}
Somehow, this works. That's great, but now I would like to understand the usage of HttpServletResponse in this context, which I am not familiar with. It seems to me that the fetch-API makes use of HttpServletResponse (maybe even creates it), since I am not creating this object or do anything with it.
What is very strange to me is that the return-type of my controller method getProfilePicture() is void, and still I am sending a response, which is most definitely not void.
Also, if the profilePicture was not found in my database, for example due to a non-existing studentId being passed, my controller-method does not do anything. But still, I am getting a response code of 200. That's why I have added the responseBlob.size > 0 part in my Javascript to check for a positive response.
Can someone explain this magic to me, please?
response.getOutputStream(); javadoc says "Returns a ServletOutputStream suitable for writing binary data in the response." It's literally the response stream and you write the picture bytes into it. It's not related to the client reading the response. Alternatively you could just return a byte array which will be automatically written into the response stream and the result will be the same.
To return a different http status code you should change the method return type to ResponseEntity<byte[]>:
#GetMapping("student/pic/studentId")
public ResponseEntity<byte[]> getProfilePicture(#PathVariable Long studentId, HttpServletResponse response) throws IOException {
Optional<ProfilePicture> profilePicture = profilePictureService.getProfilePictureByStudentId(studentId);
if (profilePicture.isPresent()) {
return ResponseEntity.ok(profilePicture.get().getPicture()); //status code 200
} else {
return ResponseEntity.notFound().build(); //status code 404
}
}
ResponseEntity is basically springs way to return different status codes/messages.
Is there a reason why you are manually downloading the image via javascript? You could just create a img element with the http link to the image and the browser will automatically display the image content: <img src="http://localhost:8080/student/pic/studentId">

WebClient's bodyToMono on Empty Body Expected Behavior

What is the expected behavior when WebClient bodyToMono encounters an empty body? In my specific example we are checking the status returned from a post call, and if it's an error converting it to our custom error format. If the conversion to the custom error format fails, we create a new error in our custom format stating that. But when a response came in that was an error with an empty body, it failed to send any error back at all because bodyToMono didn't fail as I had expected. See the below code block:
.retrieve()
.onStatus(HttpStatus::isError) { response ->
response.bodyToMono(ErrorResponse::class.java)
.doOnError {
throw APIException(
code = UNEXPECTED_RESPONSE_CODE,
reason = it.message ?: "Could not parse error response from Inventory Availability",
httpStatus = response.statusCode()
)
}
.map {
throw APIException(
reason = it.errors.reason,
code = it.errors.code,
httpStatus = response.statusCode()
)
}
}
To fix this we added the switchIfEmpty.
.retrieve()
.onStatus(HttpStatus::isError) { response ->
response.bodyToMono(ErrorResponse::class.java)
.switchIfEmpty { throw RuntimeException("Received Empty Response Body") }
.doOnError {
throw APIException(
code = UNEXPECTED_RESPONSE_CODE,
reason = it.message ?: "Could not parse error response from Inventory Availability",
httpStatus = response.statusCode()
)
}
.map {
throw APIException(
reason = it.errors.reason,
code = it.errors.code,
httpStatus = response.statusCode()
)
}
}
My question is this: Is this expected behavior from bodyToMono? Since I'm explicitly asking to map the response body to my object of ErrorResponse, I would expect an empty body to error and then hit the doOnError block, but instead it just "succeeds"/returns an empty mono...hence us adding the switchIfEmpty block. If the object we were mapping to had nullable fields, I could see it not having an error, but since all fields are required why does bodyToMono not throw an error when trying to map "nothing" to my object?
This is correct. A Mono can produce 0..1 elements and an empty body just produces a mono that completes without emitting a value, much like Mono.empty().
If no body is an error in your use case you can call .single() on your mono.

SOAP UI response

I want to view the response for the below method in SOAP UI. The url would be as below to call the accountDetails(..) method in SOAP UI to check the response.
http://localhost:8080/AccountInfo/rest/account/0003942390
#RequestMapping(value = /accountDetails/{accNum}, method = RequestMethod.GET)
public void accountDetails(#PathVariable final String accNum)
{
final boolean accountValue = service.isAccountExists(accNum);
if (!accountValue )
{
throw new Exception();
}
}
The method is executed correctly but the response i'm getting in SOAP UI is 404.
accountDetails(..) method return type is void, so do i need to set any extra parameters when i have to check the response for the method in SOAP UI with void return type to show success message.
Below is the message shown in SOAP UI:
HTTP/1.1 404 /AccountInfo/WEB-INF/jsp/account/0003942390/accountInfo.jsp
Server: Apache-Coyote/1.1
Is the exception thrown? If yes, how does the framework handle the exception?
Your method doesn't return anything - see here. Based on the RESTful nature of the URL it seems the method should return something like an AccountDetail. However, if you really just want to see the 200 then just return something like a non-null String.

Empty request body gives 400 error

My Spring controller method looks something like this:
#RequestMapping(method=RequestMethod.PUT, value="/items/{itemname}")
public ResponseEntity<?> updateItem(#PathVariable String itemname, #RequestBody byte[] data) {
// code that saves item
}
This works fine except when a try to put a zero-length item, then I get an HTTP error: 400 Bad Request. In this case my method is never invoked. I was expecting that the method should be invoked with the "data" parameter set to a zero-length array.
Can I make request mapping work even when Content-Length is 0?
I am using Spring framework version 4.1.5.RELEASE.
Setting a new byte[0] will not send any content on the request body. If you set spring MVC logs to TRACE you should see a message saying Required request body content is missing as a root cause of your 400 Bad Request
To support your case you should make your #RequestBody optional
#RequestMapping(method=RequestMethod.PUT, value="/items/{itemname}")
public ResponseEntity<?> updateItem(#PathVariable String itemname, #RequestBody(required = false) byte[] data) {
// code that saves item
}

Return a list of error messages with 400 Bad Request response in Web API 2

How can I return a list of error messages from Web Api 2 with 400 Bad Request status code? See the example below. Usually I use BadRequest method to return the 400 status code but it doesn't have any overload where it accepts a collection of string. It has an overload where it accepts ModelStateDisctionary. Does it mean I will have to create ModelStateDictionary from a list of error messages?
[Route("")]
[HttpPost]
public IHttpActionResult Add(Object data)
{
var valid = _serviceLayer.Validate(data);
if(!valid)
{
var errors = valid.Errors;
// errors is an array of string
// How do I return errors with Bad Request status code here?
}
var updatedObject = _serviceLayer.Save(data);
return Ok(updatedObject);
}
As per Mike's comment, I am going to add a new class implementing IHttpActionResult to return a list of error messages with 400 Bad Request. Thanks Mark

Resources