Angular 6 error handlig - HttpErrorResponse has undefined status - json

I have a Angular 6 client consuming a REST Api developed with .Net Web Api.
Everything is working except for the error handling. When I try to process the error to react differently to different status codes (404, 403, 409, 500...) I simply can't make it work. The HttpErrorResponse object doesn't have any of the fields it is supposed to (like 'status' or 'error').
I've made a super simple service that reproduces the issue:
Request on the service.ts
public test(): Observable<any> {
let url = this.templatesUrl + '/myMethod';
console.log('GET myMethod ' + url);
return this.http.get<any>(url)
.pipe(catchError(this.handleError));
}
Error handler (pretty much straight from the official documentation):
private handleError(error: HttpErrorResponse) {
console.warn(error);
if (error.error instanceof ErrorEvent) {
// A client-side or network error occurred. Handle it accordingly.
console.error('An error occurred:', error.error.message);
} else {
// The backend returned an unsuccessful response code.
// The response body may contain clues as to what went wrong,
console.error(
`Backend returned code ${error.status}, ` +
`body was: ${error.message}`);
}
// return an observable with a user-facing error message
return throwError('Unexpected error');
}
Service on the .Net side:
[HttpGet]
[Route("myMethod")]
public IHttpActionResult myDotNetMethod()
{
return InternalServerError(new Exception("Details about the issue"));
}
The service is called and it returns a status code 500 along with a json object:
The status of the response:
The response header, it is json:
The json object:
And what the log shows: no status and pretty much an empty object:
Loosk like the HttpErrorResponse is pretty much empty. But the response from the API was fine, the status code is there and the json object too.
What am I missing?
Update: In case you are wonder what hides behind that "Internal Server Error" that shows in the log (it is just the callstack generated by chrome):
Update 2: Here's the error object under the microscope. It is simply "Internal Server Error". No trace of status or message.

Solved... the object was empty due to an interceptor. So if something similar is happening to you check those out.
I'm sorry to have wasted everyone's time, I was unaware of the existance of that particular interceptor.

I think your problem is how you are throwing the error in .Net.
Try this:
var statusCode = HttpStatusCode.InternalServerError;
var response = new HttpResponseMessage(statusCode)
{
Content = new ObjectContent<object>(
new
{
Message = "Error Message",
ExceptionMessage = "StackTrace"
},
new JsonMediaTypeFormatter())
};
throw new HttpResponseException(response);
Or if it does not work try this: https://stackoverflow.com/a/28589333/8758483
Another good idea is to centralize your error handling by implementing an ErrorHandler in Angular.
import { ErrorHandler } from '#angular/core';
#Injectable()
export class GlobalErrorHandler implements ErrorHandler {
handleError(error) {
// your custom error handling logic
}
}
Then you tell Angular you want to use this class instead of the default one by providing it in you NgModule:
#NgModule({
providers: [{provide: ErrorHandler, useClass: GlobalErrorHandler}]
})
If you want more detail you can read this article:
Expecting the Unexpected — Best practices for Error handling in Angular

In the response the property is called "Message" and not "message".

Related

Flutter API throwing Exception

I was practicing this covid-19 tracker application using flutter from a tutorial on YouTube, so after writing a few code when I hit the API and run the application, it throws this exception, I don't understand why as I am a beginner and a newbie on Flutter.
import 'dart:convert';
import 'package:covid_tracker/Model/world_states_model.dart';
import 'package:http/http.dart' as http;
import 'Utilities/app_url.dart';
class StatesServices {
// async means waiting for your request
Future<WorldStatesModel> fetchWorldStatesRecords() async {
final response = await http.get(Uri.parse(AppUrl.worldStatesApi));
if (response.statusCode == 200) {
var data = jsonDecode(response.body);
return WorldStatesModel.fromJson(data);
} else {
throw Exception('Error');
}
}
}
class AppUrl {
// this is our base url
static const String baseUrl = 'https://disease.sh/v3/covid-19';
// fetch world covid states
static const String worldStatesApi = '${baseUrl}all';
static const String countriesList = '${baseUrl}countries';
}
You are getting a status code that's not 200. Therefore your application throws an error, just as you have programmed it!
The first step would be to actually figure out why you are getting a different status code from 200. Looking at your code it seems that you try to visit '${baseUrl}all'. This translates to https://disease.sh/v3/covid-19all. This URL however does not exist.
To fix your issue try adding a / after ${baseUrl}. Such that it becomes '${baseUrl}/all'. Or add the change the baseUrl variable to https://disease.sh/v3/covid-19/. After that, your error should be resolved.
I recommend printing to the console what links you are trying to load. It would probably prevent this kind of issue in the future. Or even more useful, include it in the exception you throw. :)
if stataus !=200 from API,
You are throwing exception in this line
throw Exception('Error');
it shows API is not returning the needed data.
Try to change line
static const String baseUrl = 'https://disease.sh/v3/covid-19';
to
static const String baseUrl = 'https://disease.sh/v3/covid-19/';

Nestjs throw exception from empty result in the controller

I have a control that calls a service.
If the service returns an empty payload from the db I want to throw an exception.
at the moment I am doing that in the service:
this is the service I have at the moment with the exception.
async getPreferences(eUserId: string): Promise<UserPreferences> {
const userPreferences = await this.userPreferencesModel.findOne({
eUserId,
});
if (!userPreferences) {
throw new NotFoundException("We couldn't find your user preferences");
}
return userPreferences;
}
I want the controller to handle the exception, The issue is that the controller response is a Promise.
How can I handle that?
This is what I shave done:
#Get()
async getPreferences(
#Headers('x-e-user-id') eUserId: string,
): Promise<UserPreferences> {
const userPreferences = this.userPreferencesService.getPreferences(eUserId);
console.log('userPreferences: ', userPreferences);
// Here is what I am trying to monitor...
if (userPreferences) {
throw new NotFoundException("We couldn't find your user preferences");
}
return userPreferences;
}
Ther console.log in the controller returns:
userPreferences: Promise { <pending> }
Now, if the service response is empty no exception is thrown.
How can I monitor the service result in order to throw an exception
Multiple ways you can solve this. Here's one.
Don't throw an error in your service, just return the result or null.
async getPreferences(eUserId: string): Promise<UserPreferences | null> {
return this.userPreferencesModel.findOne({
eUserId,
});
}
Then in your controller await for the result, you forgot this. That's why you are seeing a pending promise. After the result has been resolved, check if any user preferences were returned and throw the NotFoundException if not.
#Get()
async getPreferences(#Headers('x-e-user-id') eUserId: string): Promise<UserPreferences> {
const userPreferences = await this.userPreferencesService.getPreferences(eUserId);
if (!userPreferences) {
throw new NotFoundException("We couldn't find your user preferences");
}
return userPreferences;
}
I would not throw NotFoundException or any other HTTP related error from your service. Leave that responsibility up to your controller, don't tie your service (logic) to HTTP error codes. Throw errors here that are not aware of the context (HTTP) they are being used in.
PS: You might also consider passing the user ID via the query string or as a route parameter instead of via the headers.

Httpclient request in angular json error

I am doing http client request
export class MapjsonService{
theUrl = 'http://localhost:4200/api/Lat_Long.json';
constructor(private http: HttpClient) { }
fetchNews(): Observable<any>{
return this.http.get(this.theUrl)
}
It is working about 99.99% of the time sadly this is running so often that is fails like once every 10 mins with
HttpErrorResponse {headers: HttpHeaders, status: 200, statusText: "OK", url: "http://localhost:4200/api/Lat_Long.json", ok: false, …}
and
"Http failure during parsing for http://localhost:4200/api/Lat_Long.json"
Now I figured out for some reason my nrql query from newrelic (which is what is being stored in '/api/lat_long.json' does not have the final closing '}' once every orange moon. and this is what is throwing this error. my question is there any whay for me to check if the returned value is valid json and if it is not try the GET request again without terminating the process that called it. Thx
Your code is throwing an error because the json is not correct, therefore it can't be parsed, and therefore the observable throws an error:
fetchNews(): Observable<any>{
return this.http.get(this.theUrl)
}
By default, the http client expect json because that's usually what users expect from it. It's not always the case, like the situation you are in right now.
We can tell the http client not to parse the json on its own by specifying what we want from it using the {responseType: 'text'} parameter.
fetchNews(): Observable<any>{
return this.http.get(this.theUrl, {responseType: 'text'})
}
But then you need to parse the json when possible. So we will map the observable and parse the content here if possible.
fetchNews(): Observable<any>{
return this.http.get(this.theUrl, {responseType: 'text'}).map(res => {
try{
return JSON.parse(res);
} catch {
return null;
}
})
}
Then do whatever you want, the value returned by the observable will be null if it can't be parsed.
RXJS 6 syntax:
fetchNews(): Observable<any>{
return this.http.get(this.theUrl, {responseType: 'text'}).pipe(
map(res => {
try{
return JSON.parse(res);
} catch {
return null;
}
})
)
}

Angular4 giving 404 for json data that exists and is publicly serving

I have a test data service written in Angular4. It currently looks like this:
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/toPromise'
#Injectable()
export class DataService {
constructor(private http: Http) { }
fetchData(){
return this.http.get('https://dinstruct-d4b62.firebaseio.com/.json').map(
(res) => res.json()).toPromise();
}
}
With thanks to "The Net Ninja" for this code, as this section of the app is basically exactly the same as the tutorial code (I prefer to have something that should be a known working example for testing purposes when building new apps)...
The problem is that though there is definitely test data at https://dinstruct-d4b62.firebaseio.com/.json, which is not hidden or firewalled in any way as far as I can tell (directly accessible via browser), when the app enters the fetchData() function, it logs:
ERROR Error: Uncaught (in promise): Error: Response with status: 404 Not Found for URL: https://dinstruct-d4b62.firebaseio.com/.json
Error: Response with status: 404 Not Found for URL: https://dinstruct-d4b62.firebaseio.com/.json
at the start of the stack trace. What could be going on here?
Update:
I also noticed that in the calling function:
ngOnInit(): void {
this.customerService.getCustomers()
.then(customers => this.customers = customers);
this.dataService.fetchData().subscribe(
(data) => console.log(data));
}
When I have this.dataService.fetchData().subscribe((data) => console.log(data)); in the code, clicking a link to the dashboard it momentarily shows localhost:3000/dashboard in the browser address bar but then immediate flicks back to showing the previous URL. However, when I remove this line, the app correctly shows localhost:3000/dashboard the whole time. I assume this is probably related to the console.logged 404 error.
Also perplexing is that when I check the network traffic, no 404 is shown.
Update:
When the observable is change to a promise I get this output in the console:
Response {_body: Object, status: 404, ok: false, statusText: "Not Found", headers: Headers…}
headers
:
Headers
ok
:
false
status
:
404
statusText
:
"Not Found"
type
:
null
url
:
"https://dinstruct-d4b62.firebaseio.com/.json"
_body
:
Object
error
:
"Collection 'undefined' not found"
__proto__
:
Object
constructor
:
function Object()
hasOwnProperty
:
function hasOwnProperty()
isPrototypeOf
:
function isPrototypeOf()
propertyIsEnumerable
:
function propertyIsEnumerable()
toLocaleString
:
function toLocaleString()
toString
:
function ()
valueOf
:
function valueOf()
__defineGetter__
:
function __defineGetter__()
__defineSetter__
:
function __defineSetter__()
__lookupGetter__
:
function __lookupGetter__()
__lookupSetter__
:
function __lookupSetter__()
get __proto__
:
function __proto__()
set __proto__
:
function __proto__()
__proto__
:
Body
constructor
:
function Response(responseOptions)
toString
:
function ()
__proto__
:
Object
There is still no 404 in the network traffic.
I have now updated the calling function to this:
ngOnInit(): void {
this.customerService.getCustomers()
.then(customers => this.customers = customers);
this.dataService.fetchData().then((data) => {
console.log(data);
})
.catch((error) => console.error(error));
}
The in-memory-web-api will interfere with your "outside" requests. You need to remove that from your NgModule, since otherwise Angular is always trying to look in in-memory-web-api for your requests, which obviously doesn't exist in that place. So removing the equivalent of
InMemoryWebApiModule.forRoot(InMemoryDataService)
from your ngModule and that should clear it out! :)
Try importing import 'rxjs/add/operator/toPromise';
and add toPromise to the end of the http get in the the fetchData() function.
fetchData(){
return this.http.get('https://dinstruct-d4b62.firebaseio.com/.json').map(
(res) => res.json()).toPromise();
}
Your calling function should then look like this:
this.dataService.fetchData()
.then((data) => {
console.log(data);
})
.catch((error) => console.error(error));
In AppModule.ts where you have imports[], you would have imported the HttpClientInMemoryWebApiModule
like =>
HttpClientInMemoryWebApiModule
.forRoot(
InMemoryService, { dataEncapsulation: false }
), 
Now What is happening here is that your application is searching for the public API in the in-memory web API only to solve this just tell In memory module not to behave like that by setting the passing though unknown Url true
like =>
HttpClientInMemoryWebApiModule
.forRoot(
InMemoryService, { dataEncapsulation: false, passThruUnknownUrl: true }
)

Angular 2 sees my Json object as an function

I have a webapp that gets via Json stuff put it in objects to display them.
I already did it two times with services and classes.
But now i copy and paste the old code make some slight changes to make sure it redirect to the good classes but now i get an array with functions instead an array with objects.
Here is my constructor that calls upon the the service classes and send things to the console
constructor(private featureService : FeatureService, private scenarioservice : ScenarioService, private failuresService : FailuresService){
//hier worden de features en failures opgehaald
this.featureService.getFeatures().subscribe(res => {
this.featureArray = res.getFeatureArray();
console.log(res.getFeatureArray());
});
this.failuresService.getFailures().subscribe(res => {
this.failureArray = res.getFailureArray();
console.log(res.failures[0].method);
console.log(this.failureArray);
});
}
}
Here is failuresService.getFailures:
import { Injectable } from "#angular/core";
import {Http, Response} from "#angular/http";
import {Failure} from "./Failure";
import {Failures} from "./failures";
#Injectable()
export class FailuresService {
constructor(protected http: Http) {}
getFailures() {
return this.http.get('http://localhost:8080/testresultaten')
.map((response: Response) => response.json())
.map(({failures = [Failure]}) => new Failures(failures));// deze error is bullshit
}
}
This is the Json that I get and want to get in an class:
{
"failures:": [
{
"method": "canRollOneGame",
"object": "BowlingGame.GameTest"
},
{
"method": "canCountNighteeneight",
"object": "FizzBuzz.FizzBuzzTest"
}
]
}
Here are the Failure and Failures classes:
import {Failure} from "./Failure";
export class Failures {
constructor(public failures : Failure[]){}
public getFailureArray(): Failure[]{
return this.failures;
}
}
export class Failure{
constructor(public method : String , public object : String ){ }
}
I could be wrong but this doesn't look right:
getFailures() {
return this.http.get('http://localhost:8080/testresultaten')
.map((response: Response) => response.json())
.map(({failures = [Failure]}) => new Failures(failures));// deze error is bullshit
}
That last mapping, I'm not sure what it is supposed to do. I've never seen that syntax (doesn't mean it's wrong). I get that you have an incoming array. But what this syntax does {failures = [Failure]} is what I think your problem is. I don't think that will do what you think.
Try this and see what happens:
.map(failures => { console.log ( failures ); new Failures(failures) } );// deze error is bullshit
If you try that with your old mapping, and then this new one, it'd be interesting to see what that console.log traces out. I think doing it your way, you won't see what you expect.
If that sorts you out, then you can try typing the incoming payload (though I'm not sure it'll work; it should be receiving JSON from the previous mapping).
.map( (failures: Array<Failure>) => { console.log ( failures ); new Failures(failures) } );
So if I read it correctly: Your goal is to create an array of Failure objects with the values coming from a JSON array where each of this has a method you'd like to execute somewhere in the code.
If thats the case then I understand what went wrong. As Tim Consolazion mentioned in the comments you only get the values for the Failure object not the Failure object itself (See custom created method error: "is not a function"). So in order to execute the commands from Failure you have to create for each object in your JSON array a Failure object. Something like this:
return this.http.get('http://localhost:8080/testresultaten')
.map((response: Response) => {
let content = response.json();
let failureList: Failure[] = [];
content.forEach(failure => {
failureList.push(new Failure(failure.method, failure.object))
});
return failureList || {};
}
What I wonder is where you found {failures = [Failure]}? I've never seen this before and I've no idea what this is for.
EDIT: I edited the question so it fits your class Failure. The failure in content.forEach(failure => { in an object from your JSON array. You can access the values of it like it is a normal object. In your case with failure.method and failure.object.
I found my problem in the Json the name was function: but in my code it was function so all that was necessary was to make sure it sends function instead of function: