how to add a status message on a grails respond - grails

I have created a method that is called after every uncatched exception and respond a gson view:
void handleError(){
respond([status: 500, view: "/customErr"], [
code : 500,
message : "whatever internal error",
])
}
this works fine but the main problem that I have is that my client (another server acting as client) is receiving a http response with a 500 status but the status message is null. I've checked the respond docs and I don't see a property message or something.
this if what my client receive:
wslite.rest.RESTClientException: 500 null
and that null is the response's status message that is not set by grails
How can I add a detail message on my respond? idyllically something like this:
respond([status: 500, statusMessage: "my custom
message", view: "/customErr"], [
code : 500,
message : "whatever internal error",
])

grails uses Servlet API’s HttpServletResponse to build response.
now check the java doc for HttpServletResponse class.
there are only 2 methods to define status message:
void setStatus(int sc, String msg) Deprecated. As of version 2.1, due to ambiguous meaning of the message parameter. To set a status code use setStatus(int), to send an error with a description use sendError(int, String).
void sendError(int sc, String msg) Sends an error response to the client using the specified status and clears the buffer. The server defaults to creating the response to look like an HTML-formatted server error page containing the specified message, setting the content type to "text/html".
The first one is deprecated. The second one sends the status message, but it will not send the body - mainly this used for fatal errors...
So, officially by servlet documentation there is no way to send both: message and body in response.
The question is tricky. Because according to Apache Tomcat the "custom status message" feature will be removed starting from version 9: https://tomcat.apache.org/tomcat-8.5-doc/config/systemprops.html#Other
But according to RFC2616 sec 6.1.1 : The reason phrases listed here are only recommendations -- they MAY be replaced by local equivalents without affecting the protocol.

This doesn't directly answer your question, and may not solve your issue depending on how much control you have over the application that receives the error, but you can add error messages to the header of the response which should pass through to the client (if it knows to check for them).
String errorMessage = "Whatever Internal Server Error"
response.addHeader("custom-error", errorMessage)
response.sendError(500, errorMessage)
That'll send the message in the header and as the response message... I do not know if this works with respond() or how that interacts with the response object in the controller... but if you're responding to render a view as the error page, you should be able to add the message to the model included in the respond() call and show that on the error page (at least, I'd think so).

Related

how to prevent message creation api to resend complete message

I use graph api to create a message with attachment(s).
All runs fine but the server send back the complete message in response, including the attachments.
Is there a way to only get the message id in the response ?
I try with :
string webApiUrl = $"{_apiUrl}v1.0/users/{senderId}/messages?$select=id"
but I still get the whole message with 98ko of attachment.
You can do it using the prefer:return=minimal header in the request which will mean you will just get a 204 response. However the id of the item that was created will be returned in the location header (the response should really have the OData-EntityId if they are following the oData spec to the letter, also I'm not sure why it return the Outlook v2 location rather then the graph but the message Id is the same between them)

Swashbuckle refuses to show response example for HTTP 500

I'm using Swashbuckle for a web api app in .Net Core 3.1. I want response examples for various response codes. I can get all of them working except HTTP 500. These are the attributes on the a particular method:
[SwaggerRequestExample(typeof(GroupInfoRequest), typeof(GroupInfoRequestExample))]
[SwaggerResponseExample(Status200OK, typeof(GroupInfo200Example))]
[SwaggerResponseExample(Status400BadRequest, typeof(GroupInfo400Example))]
[SwaggerResponseExample(Status403Forbidden, typeof(GroupInfo403Example))]
[SwaggerResponseExample(Status404NotFound, typeof(GroupInfo404Example))]
[SwaggerResponseExample(Status500InternalServerError, typeof(GroupInfo500Example))]
[ProducesResponseType(Status200OK)]
[ProducesResponseType(Status400BadRequest)]
[ProducesResponseType(Status403Forbidden)]
[ProducesResponseType(Status404NotFound)]
[ProducesResponseType(Status500InternalServerError)]
I can get all of them to render except the GroupInfo500Example. The application only returns an HTTP 500 to indicate an internal exception that isn't caught by other exception handlers. It is intended to return a body that contains, among other things, a GUID that can be passed in to our support organization to help them look up the exception in the application logs. I can not get the example to render for any 5xx error. If I change it to another status code, it renders, so it's specifically the 5xx result that doesn't render. I've checked the openapi json produced and it's not produced as part of the generated JSON. Is there a filter in place that keeps 5xx response docs from showing response examples?
Finally figured it out. I was missing part of the 'ProducesResponseType' attribute. It needs to have the return type as well as the HTTP status code. This works:
[ProducesResponseType(typeof(ADServiceOperationMultipleResult<GroupActionRequestForUsers, UserQuery>), Status200OK)]
[ProducesResponseType(typeof(ADServiceOperationMultipleResult<GroupActionRequestForUsers, UserQuery>), Status400BadRequest)]
[ProducesResponseType(typeof(ADServiceOperationMultipleResult<GroupActionRequestForUsers, UserQuery>), Status403Forbidden)]
[ProducesResponseType(typeof(ADServiceOperationMultipleResult<GroupActionRequestForUsers, UserQuery>), Status404NotFound)]
[ProducesResponseType(typeof(ADServiceOperationMultipleResult<GroupActionRequestForUsers, UserQuery>), Status422UnprocessableEntity)]
[ProducesResponseType(typeof(ADServiceOperationMultipleResult<GroupActionRequestForUsers, UserQuery>), Status500InternalServerError)]
Oddly enough, some status codes were including the example without it, but now the examples appear consistently as long as I include the method return type in the attribute.

Are all elements in a POST requests body mandatory?

If a POST request requires that i send four data elements in the body, like:
{
"name":abc,
"surname":xyz,
"contact_no":1234,
"address":random_value
}
What will happen if I miss out some of the elements, for example if I call the web service with elements like,
{
"name":abc,
"surname":xyz,
}
What error is the server likely to throw ? I am having this issue because I am making a API call and it's giving me a HTTP error 500, so I guess it's not an error on my part, but this is one doubt i wanted to clear. Thanks in advance.
Its depends on the service structure (if all fields are mandatory or not),
and HTTP error (500) returns to server error or (server or link) not found .

Error submitting a cloud dataflow job

Since a few days ago, I'm no longer able to submit my dataflow jobs, they fail with the error below.
I tried to submit the simple WordCount job and it succeeded. Even with a very simplified version of my own job, everything is fine. But when I add more code (adding GroupByKey transform), I'm no longer able to submit it.
Does anybody have any idea what does this error mean?
Thanks,
G
Exception in thread "main" java.lang.RuntimeException: Failed to create a workflow job: Invalid JSON payload received. Unknown token.
{ 8r W
^
at com.google.cloud.dataflow.sdk.runners.DataflowPipelineRunner.run(DataflowPipelineRunner.java:219)
at com.google.cloud.dataflow.sdk.runners.BlockingDataflowPipelineRunner.run(BlockingDataflowPipelineRunner.java:96)
at com.google.cloud.dataflow.sdk.runners.BlockingDataflowPipelineRunner.run(BlockingDataflowPipelineRunner.java:47)
at com.google.cloud.dataflow.sdk.Pipeline.run(Pipeline.java:145)
at snippet.WordCount.main(WordCount.java:165)
Caused by: com.google.api.client.googleapis.json.GoogleJsonResponseException: 400 Bad Request
{
"code" : 400,
"errors" : [ {
"domain" : "global",
"message" : "Invalid JSON payload received. Unknown token.\n\u001F \b\u0000\u0000\u0000\u0000\u0000\u0000\u0000 \t{ 8r\u0000 W\n^",
"reason" : "badRequest"
} ],
"message" : "Invalid JSON payload received. Unknown token.\n\u001F \b\u0000\u0000\u0000\u0000\u0000\u0000\u0000 \t{ 8r\u0000 W\n^",
"status" : "INVALID_ARGUMENT"
}
To debug this issue, we want to validate that the request that is being made is valid and find the invalid portion of the JSON payload. To do this we will:
Increase logging verbosity
Re-run the application and capture the logs
Find the relevant section within the logs representing the JSON payload
Validate the JSON payload
Increasing logging verbosity
By adding the following lines to your main before you construct your pipeline, you will tell the Java logger implementation to increase the verbosity for the "com.google.api" package. This in turn will log the HTTP request/responses to Google APIs.
import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
public class MyDataflowProgram {
public static void main(String[] args) {
ConsoleHandler consoleHandler = new ConsoleHandler();
consoleHandler.setLevel(Level.ALL);
Logger googleApiLogger = Logger.getLogger("com.google.api");
googleApiLogger.setLevel(Level.ALL);
googleApiLogger.setUseParentHandlers(false);
googleApiLogger.addHandler(consoleHandler);
... Pipeline Construction ...
}
Re-run the application and capture the logs
You will want to re-run your Dataflow application and capture the logs. This is dependent on your development environment, what OS and/or IDE that you use. For example, when using Eclipse the logs will appear within the Console window. Saving these logs will help you maintain a record of the issue.
Find the relevant section within the logs representing the JSON payload
During re-execution of your Dataflow job, you will want to find the logs related to submission of the Dataflow job. These logs will contain the HTTP request followed by a response and will look like the following:
POST https://dataflow.googleapis.com/v1b3/projects/$GCP_PROJECT_NAME/jobs
Accept-Encoding: gzip
... Additional HTTP headers ...
... JSON request payload for creation ...
{"environment":{"clusterManagerApiService":"compute.googleapis.com","dataset":"bigquery.googleapis.com/cloud_dataflow","sdkPipelineOptions": ...
-------------- RESPONSE --------------
HTTP/1.1 200 OK
... Additional HTTP headers ...
... JSON response payload ...
You are interested in the request payload as the error you are getting indicates that it is the source of the problem.
Validate the JSON payload
There are many JSON validators which can be used but I prefer to use http://jsonlint.com/ because of its simplicity. If you are able, please share your findings either by updating the question or if you get stuck, feel free to send me a private message.

How to globally handle HTTP errors in Grails (status codes 4xx/5xx)?

Is there a way in Grails to catch all the possible HTTP errors before they're being sent to the client browser, as to be able to handle the content being sent to the client? I mean all 4xx and 5xx HTTP status codes, not only the 403, 404 and 500 like other have suggested.
What I'd like to do is to catch all HTTP errors in the first place, without having to specify them all one by one, then in a second step I would filter (e.g. in an error controller) specific error codes that I would like to handle (e.g. 400), but at least the ones that I would not specify would render to a generic error template I defined.
If this can't be done (or shouldn't be done), which HTTP errors codes should really be checked for and handled? I can at least see those codes happening at some point: 400, 401, 403, 404, 405, 500, 501, 503. And also, how should they be handled, using HTTP response codes mappings?
Thanks!
haven't actually tried it but maybe a number constraint might work?
"$errorCode" {
controller = "errors"
action = "displayError"
constraints {
errorCode(matches:/\d{3}/)
}
}

Resources