I have a superagent call to my java code. In that Java Controller - I am throwing user defined exception message as below.
In service :
if (user_id == null){
throw new Exception("User ID is missing!!!");
}
In controller:
Map<String, String> resp = new HashMap<String,String>();
try{
String returnValue= myserviceobj.myservicemethod;
}catch(Exception e){
resp.put("status","ERROR");
resp.put("message",e.getMessage());
return new ResponseEntity<Map<String,String>>(resp, HttpStatus.Bad_Response);
}
In React Js I am using superagent to make service call. I am not sure how to access that user defined exception message in UI.
Here is what I do in JS:
webservice(data, actionName, (error,resp){
if(error){
//call alert and send the user defined message.
}
})
https://developer.mozilla.org/fr/docs/Web/API/Window/alert ?
Anyway i would use Redux to check the state of my app and dispatch an alert action.
Maybe this is what your looking for : https://alexanderpaterson.com/posts/showing-and-dismissing-alerts-in-a-react-application
Related
I've been using axios recently but I can't get the error message thrown by Spring Boot RuntimeException.
I've created a simple RuntimeException which throws 404 status:
#ResponseStatus(HttpStatus.BAD_REQUEST)
public class BadRequestException extends RuntimeException {
public BadRequestException(String message) {
super(message);
}
}
I make a GET request to one of my endpoint where all it does is throw the BadRequestException with some message:
#RestController
public class TestController {
#GetMapping("/throw")
public ResponseEntity<?> throwError() {
throw new BadRequestException("This text should be in statusText");
}
}
console.log() from the catch clause (.catch((error) => console.log(error.response))) is:
As you can see, the statusText is just an empty string, where "This text should be in statusText" should be expected.
Using fetch() works perfectly fine, but switching from axios to fetch in my situation will be time-wasting.
Am I missing something? Do I even throw the exceptions with my messages correctly?
Thanks in advance for all answers!
Note that HTTP/2 doesn't support status text messages, so you'll always get an empty one on a HTTP/2 connection (often this means you get them in development but they're empty in production). https://developer.mozilla.org/en-US/docs/Web/API/Response/statusText
This is a doPost function inside a Google App that returns a Hello World message.
function doPost(e){
return ContentService.createTextOutput('Hello World');
}
Now suppose I want to only accept valid JSON to be posted to this Google App endpoint and I want to send a respones with Bad Request status. How can I do that. Here's the pseudo code:
function doPost(e){
try{
const data = JSON.parse(e.postData.contents);
return ContentService.createTextOutput('Hello World');
}catch(err){
// Send Bad Request
}
}
Issue and workaround:
Unfortunately, in the current stage, ContentService cannot modify the status code. When I saw the official document of Class ContentService, such method cannot be found. Ref It seems that this is the current specification.
So in your situation, as the current workaround, how about returning the value as JSON data? By this, you can check the value using the key of JSON data. For example, how about the following sample script?
When the correct value without the error is returned,
return ContentService.createTextOutput(JSON.stringify({value: 'value'}));
When the value with the error is returned,
return ContentService.createTextOutput(JSON.stringify({error: 'Error message'}));
When you need .setMimeType(ContentService.MimeType.JSON), please add this.
Note:
When I searched about this at the Google issue tracker, I couldn't find it. So how about reporting this as the future request? Ref
Reference:
Class ContentService
Here's another workaround that allows raising errors on the client side for errors on the web app side. For example, a client might need to catch errors such as bad url args sent to the web app (i.e. the OP's question), or catch errors thrown by a method that is called from doGet() or doPost().
As far as I know, when an error is thrown downstream of doGet() or doPost(), a text error message is returned in the response, but the web app request itself succeeds, so there is no error thrown on the client side. As #Tanaike said, there still seems no way for a Google web app dev to throw an HTTP error from the app (like 400 Bad Request or 500 Internal Server Error).
The idea involves returning a function body from the web app, which the client can use to create and run a dynamic function via the Function() constructor (this assumes Javascript is available on the client).
So the web app can be written to:
return a function body that will throw an error for bad args, server method errors, etc.
return a function body that will return intended JSON when there is no error
This is a bit of a hack, but it unifies error handling on the client side. The client makes the http request, constructs a function using the function body returned in the response, and then runs this function, all in one try{} block. Then both Google-raised http errors and web app downstream errors can be caught in the catch{} block.
Example setup for a Google Apps Script client making a request to a Google web app:
(1) In the web app doGet() or doPost() function:
// this string will be returned by the webapp
var fnBody;
// for bad url args, return a fnBody that will throw an error with an indicative message
if(!urlArgsOk()) {
fnBody = "'use strict'; throw new Error('POST args error');";
}
// if url args are ok, call server method
else {
try {
// if the method call succeeds, return a fnBody that will return the intended JSON
var returnObj = myServerMethod(methodArgs);
fnBody = "'use strict'; return JSON.stringify(" + JSON.stringify(returnObj) + ");";
}
catch(serverErr) {
// if the method call fails, return a fnBody that will throw an error ...
// ... simple example shown here, but info from serverErr can be included in fnBody
fnBody = "'use strict'; throw new Error('server error');";
}
}
// return fnBody, which can be run via Function() on the client
return ContentService.createTextOutput(fnBody).setMimeType(ContentService.MimeType.TEXT);
(2) On the client side (Google apps script client making a POST request)
// Set the url, payload, and fetch options
var url = "https://script.google.com/_______/exec?arg1=val1&arg2=val2";
var payload = getPayloadString(); // whatever POST payload needs to be sent
var options = {
'method' : 'POST',
'contentType': 'application/json',
'muteHttpExceptions': false, // let Google http exceptions come through
'payload' : payload,
'headers': {authorization: "Bearer " + ScriptApp.getOAuthToken()}
};
// Send a request to the web app
try {
// make the POST request - this throws Google-generated HTTP errors if any
var response = UrlFetchApp.fetch(url, options);
// create the dynamic function from the fnBody returned
var responseFn = new Function(response.getContentText());
// run the function - this returns intended JSON content
// or throws web app downstream errors if any
var responseJson = responseFn();
}
catch(err) {
// handle either source of error
console.log(err.message);
}
There are potential security risks associated with dynamic code, so I'm not sure how widely applicable this might be. I might use this in an aplication that lives entirely in a private GCP domain, i.e. with the web app restricted to same-domain users and the client app also in the same domain. Some security is also added by the 'use strict' directive, which boxes the dynamic function in by setting its this to undefined (ref). But it's still a good idea to think through the dynamic code implications (ref1, ref2).
Say I have a spring:form binded with MyObject class and on submit I hit this Controller method:
#PostMapping(value = "/saveObject")
public String saveInterest(#ModelAttribute("myObject") MyObject myObject, BindingResult result,
ModelMap model, RedirectAttributes redirectAttrs, HttpServletRequest request, HttpServletResponse response,
HttpSession session) throws Exception {
try {
// MY NEED IS HERE
myService.saveMyObject(myObject);
} catch (Exception e) {
throw new Exception("error when trying to save my object");
}
return "redirect:/dasboard";
}
What I want to achieve is passing myObject to an external application too on submit, by that I mean opening this external application in a new tab with myObject filling a similar spring:form.
Here is what I did so far :
Created a Restful Web Service client that hits an external application controller in which I receive myObject and fill a spring:form with it before returning a ModelAndView.
My question is how can I implement this new tab behavior, am I missing something obvious ?
i am trying to introduce Angular into one of my old application. But not sure why this is not calling the Service. Below is the Code in the JS File. Earlier i got error in browser saying $http cannot be resolved . So i just passed it in the function.
var app = angular.module('ldlApp', []);
app.controller('ldlController', function($scope,$http) {
console.log(" Inside Controller **** ");
$scope.message = 'Hello from LDL Controller !!!! ';
$scope.BLT_LDL_DECESION_LOAN_DATA = [];
console.log(" Going to Hit the Service ***** ");
$http.get("/Services/ldl/getdetails")
.then(function(response) {
$scope.BLT_LDL_DECESION_LOAN_DATA = response.data;
console.log("BLT_LDL_DECESION_LOAN_DATA:
"+JSON.stringify($scope.BLT_LDL_DECESION_LOAN_DATA));
});
});
Below is the REST Controller in java File
#RestController
public class LoanDecesionController {
#RequestMapping(value = "/Services/ldl/getdetails", method = RequestMethod.GET)
#ResponseBody
#Transactional
public List<LinkedHashMap<String, Object>> getdetails() throws Exception {
System.out.println(" Inside Service **** ");
List<LinkedHashMap<String, Object>> dataMap = new ArrayList<LinkedHashMap<String, Object>>();
LinkedHashMap<String, Object> responsedataMap = new LinkedHashMap<>();
responsedataMap.put("SUCESS", "Called the service ");
dataMap.add(responsedataMap);
return dataMap;
}
}
In Browser i could see message like
Inside Controller ****
Going to Hit the Service *****
Below is something i am seeing in network tab .
Request URL: https://*****-*****-*****.com/Services/ldl/getdetails
Request Method: GET
Status Code: 302 Found
Remote Address: 10.***.***.49:553
Referrer Policy: no-referrer-when-downgrade
But i am not getting the sysouts in controller. So whether the problem is really with response or is it hitting the service.
when using #Transactional and #ResquestMaping spring boot don't auto-configure URL mappings. remove #Transactional from your method and try to manage transactions somewhere else in your code
It looks like my existing application is blocking the URL and not allowing to hit any other URLs . Thanks everyone for the help and giving insight to the problem.
I have a service call that when it returns a 404 error, I want to display the message that comes from the server when the status is 404. So, in event of an error or success, I get a post json that gives me a status code and message that indicates if it was successful or not.
Currrently, I have this service call:
this._transactionService.findExistingTransaction(user, searchNumber)
.subscribe(data => {
this.transactionResponse = data;
console.log(JSON.stringify(this.transactionResponse));
this.router.navigate(['/edit-transaction-portal'], {queryParams: {bill: searchNumber}});
this.onDismiss();
}, (err) => { this.displayErrors = true;});
on error, it will set the bool displayErrors = true and then I can show the error message in my UI.
In html code:
<input #inputtedNumber class="transactionInput" placeholder="{{numberPlaceholder | translate }}"/>
<div class="error-msg1" *ngIf="displayErrors" style="margin-left:90px;" name="errorMsg">
{{transactionResponse._errorDetails._message}} </div>
This is the json that gets posted back when I directly try to access api endpoint:
{
"_transactionNumber":null,
"_order":null,
"_errorDetails":{
"_status":"404",
"_message":"Number is not available"
}
}
I bind to the transactionResponse object that I get back from my service call. Unfortunately, although I believe this should work, I get the issue that _errorDetails is undefined and so nothing shows up.
I wonder if this is the right setup for something like this? If now, how can I fix it?
Thanks!
EDIT: Duplicate SO post with no answer: How to read Custom error message from backend in Angular 4/2
The response body from the server should be in the error property of the error response that comes back in the error callback.
Regarding HttpErrorResponse, the documentation states:
A response that represents an error or failure, either from a non-successful HTTP status, an error while executing the request, or some other failure which occurred during the parsing of the response.
Any error returned on the Observable response stream will be wrapped in an HttpErrorResponse to provide additional context about the state of the HTTP layer when the error occurred. The error property will contain either a wrapped Error object or the error response returned from the server.
If you want to use the same transactionResponse to display the errors, then assign the error property of the err that comes back to this.transactionResponse.
Service Call
this._transactionService.findExistingTransaction(user, searchNumber).subscribe(
(data) => {
this.transactionResponse = data;
console.log(JSON.stringify(this.transactionResponse));
this.router.navigate(['/edit-transaction-portal'], {queryParams: {bill: searchNumber}});
this.onDismiss();
},
(err: HttpErrorResponse) => {
this.displayErrors = true;
// assign the error property of the err that comes back to the transactionResponse
this.transactionResponse = err.error;
});
HTML
Then this will work.
<input #inputtedNumber class="transactionInput" placeholder="{{ numberPlaceholder | translate }}"/>
<div class="error-msg1" *ngIf="displayErrors" style="margin-left:90px;" name="errorMsg">
{{transactionResponse._errorDetails._message}}
</div>
There was some work done to this part of Angular in September 2017. parse error response body for responseType "json" So you may need to update Angular depending on your version.
This solution was tested on the following:
Node v8.2.1
NPM v5.3.0
Angular CLI: 1.7.2
Angular: 5.0.0
Edit: StackBlitz example
HttpErrorResponse StackBlitz example
This example makes some assumptions about what the service looks like and what endpoint it is calling. The service makes a POST call to www.google.com. This fails and returns an HttpErrorResponse.
{
"isTrusted": true
}
The error property of the HttpErrorResponse is assigned to this._transactionResponse. This can then be accessed in the template and displayed in the browser.
Your problem is that in the event of an error, your
data => {
this.transactionResponse = data;
code does not get called - you got an error response, not a normal response afterall.
Try to get the information from the
}, (err) => { this.transactionResponse = err
part.
I think you can use a typed response:
On your error notification type you could have something like:
err => {
this.localErrorResponse = err as ErrorResponse;
this._order= this.localErrorResponse._order;
}
inside your class, also, you could have:
import { ErrorResponse } from './error-response';
localErrorResponse: ErrorResponse;
_order: string;
and then, you could have your ErrorResponse class like:
import { ErrorDetail } from './error-detail';
export class ErrorResponse{
_transactionNumber: number;
_order: string;
_errorDetails: ErrorDetail;
}
and class ErrorDetail
export class ErrorDetail {
_status: number;
_message: string
}
then you can map some other variables, as _order (this._order), or get them from your localErrorResponse (this.localErrorResponse) variable
I have a service call that when it returns a 404 error, I want to
display the message that comes from the server when the status is 404
...
I bind to the transactionResponse object that I get back from my
service call. Unfortunately, although I believe this should work, I
get the issue that _errorDetails is undefined and so nothing shows up.
Try this:
StackBlitz EXAMPLE