Axios statusText is always empty - javascript

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

Related

request.getParameter return null

I work on spring boot and angular I made an authentication based on spring security I tested with postman and everything works fine, but when I use angular it does not work after debugging I noticed that request. getParameter("username") return null, the error is probably on the angular request, please can someone help me
#Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
// TODO Auto-generated method stub
String username = request.getParameter("username");
System.out.println(username);
String password = request.getParameter("password");
System.out.println(password);
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(username, password);
return authManager.authenticate(authToken);
}
//req angular
login(params:any) : Observable<any> {
let username=params.username as string
let password=params.password as string
const FORM_URL = {
headers:{
'Content-Type': 'application/json'
}
}
return this.http.post<any>(`${this.adresse+'/login'}`,{
'username':username,
'password':password
}, FORM_URL)}
}
According to the documentation:
Returns the value of a request parameter as a String, or null if the parameter does not exist.
Find out where this parameter should come from. Candidates are the client request, the container and the Sprint Boot framework. Once you know which side is supposed to set it, figure out why it does not.
One answer can be as simple as 'the user has not yet authenticated'. For a more focused response you'd have to share more details.

How can I get my fetch error to show an http status code?

I have a react component and I'm making a network call to set the state. Eventually I want to pass this down to other child components, but just getting the plumbing to work at the moment.
I'm trying to catch errors correctly when calling out to my backend (an express server in the app). I attempted to force an error by fetching data from an endpoint that doesn't exist. This should throw a 404 since it doesn't exist, right? How can I get that error surfaced in the catch statement? Right now my error is SyntaxError: Unexpected token < in JSON at position 0 at eval (app.js:61)
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
data: null
};
}
componentDidMount() {
fetch('/api/wrong_endpoint').then((data) => {
return data.json();
}).then((body) => {
this.setState({data: body})
}).catch(err => console.log(err));
}
render() {
console.log('logging the states');
console.log(this.state.data);
return (
<div>
<ContactList />
<ContactDetail />
<AddContactModal />
</div>
);
}
}
I'll try to go step by step
fetch method doesn't throw an error even if you get the 4xx or 5xx response codes. Please read about the Fetch API carefully, I believe you can find a lot of interesting you don't know about it.
You can easily check the response status as follows (please read about the Response object and its methods/properties):
fetch('/api/wrong_endpoint').then((response) => {
console.log('status code', response.status)
})
It's hard to say if your server really returns 404 code because I don't know your express setup. If you set some fallback handler like app.get('*', ...) then it might as well return 200 success code. You can check the response status and its body in devTools of the browser. But I believe it's better if you configure at least your /api router to return 404 error if the requested /api/... route isn't found.
What I'm really sure of is that your server returns some HTML layout in the response. And you try to parse it as JSON string via data.json() and of course you get the syntax error since it's not JSON (html layout starts with < symbol hence the error: SyntaxError: Unexpected token <)
Generally, if you are using the fetch API, errors 40x and 50x will not go into the subsequent blocks, as the promise from fetch only rejects network errors (not HTTP errors or anything else). Therefore, requesting for data from an 'incorrect' endpoint will be handled within the first then block.
I would recommend you to use check your http response body based on the Response.Ok property. Successful responses will be handled within that condition, whereas any other responses (ok: false) will be handled on the other statement.
fetch('/api/wrong_endpoint')
.then(response => {
console.log(response) // full response body
console.log(response.status); // get only the response.status
if (!response.ok) {
// http errors 40x and 50x will go into this statement
// do something to handle it
} else if (response.ok) {
// handles status code 200
}
})
.then(
// ...

How do I get the post json when there is a 404 error?

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

Send user defined error message to React JS from responseEntity

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

Difference between JSON.parse and .json() in Javasscript

I have a simple angular2 http get call like below
import { Http, Response } from '#angular/http';
#Injectable()
export class ServiceBase {
protected resource: string;
constructor(private _http: Http) { }
getTnCByCountryCodeNdType(countryCode: string, tncType: string) {
let url = `${CONFIG.URL}/tnc?countryCode=${country}&tnc=${tnc}`;
return this._http.get(url, this.getHeader())
.map((res: Response) => {
return res.json();
});
}
}
The Error response from the above when received,
I tried
this.service
.getTnCByCountryCodeNdType('MY', this.tnc.toLowerCase())
.subscribe(x => {
//
},
(err: Response) => {
error = JSON.parse(err);
});
where: err is the response error;
and it threw the usual json error .
EXCEPTION: Unexpected token R in JSON at position 0
To my surprise
error = err.json();
Works fine. What is the difference between the two and why does the first one failed? Any help is appreciated
JSON.parse is a JavaScript thing. It parses a string containing JSON into whatever that string represents. You don't pass it objects. Clearly, your err isn't a string.
The res and err that Angular 2's http gives you are Response objects, which says it derives from Body. I can't see anything in the Angular 2 docs saying what Body is, but clearly it has a json function that returns the result of parsing the response data as JSON. That's not a JavaScript thing, that's something from Angular. (As noted in the link above, it's inspired by — but not the same as — fetch.)
JSON.parse expects a JSON-formatted string, but you give it a Response object, which is not JSON, hence the parsing error.
res.json() extracts the JSON-formatted data from the Response object and converts the data into a JavaScript object.

Categories