Adapter error when connection is lost - javascript

When my application loses the internet connection, I get an error coming from the adapter and I'm not sure why it does that.
Error: Adapter operation failed
at new Error (native)
at Error.EmberError (http://localhost:5966/assets/vendor.js:25883:21)
at Error.ember$data$lib$adapters$errors$$AdapterError (http://localhost:5966/assets/vendor.js:66151:50)
at ember$data$lib$system$adapter$$default.extend.handleResponse (http://localhost:5966/assets/vendor.js:67455:16)
My application adapter looks like this:
export default DS.JSONAPIAdapter.extend(DataAdapterMixin, {
host: config.apiUrl,
handleResponse(status, headers, payload) {
if (status === 422 && payload.errors) {
return new DS.InvalidError(payload.errors);
}
return this._super(...arguments);
}
});
The error action in my application route never gets triggered.
export default Ember.Route.extend({
actions: {
error(error, transition) {
console.log(error, transition); //Never displayed
}
}
});
I'm making the call to the store in my controller.
export default Ember.Controller.extend({
actions: {
getUsers() {
this.get('store').findAll('user').then((users) => {
this.set('users', users);
});
}
}
});
Any idea how to fix this error and trigger the error hook in my route?
Thanks

I think you have to catch the error yourself so it doesn't get caught by the ember data implementation.
getUsers() {
this.get('store').findAll('user').then((users) => {
this.set('users', users);
}).catch((error) => {
// Add some custom error handling or do nothing to prevent the exception from getting thrown
});
}
Also your error hook in the route will only get fired when a promise in a transition (for example in one of the model hooks) rejects. If you have a promise in a controller you have to trigger the action/event yourself.

Related

Possible Unhandled Promise Rejection (id: 0): ReferenceError: error is not defined

//LoginScreen.js
import signIn from "amplify-communication"
const LoginScreen = props => {
function _signIn(username, password){
const request = signIn(username, password);
if(request.isCommited)
console.log("User is Signed In");
else
console.log("Error Signing In", request.message);
}
}
// amplify-communication.js
import { Auth } from "aws-amplify";
export async function signIn(_username, _password) {
try {
var user = await Auth.signIn(_username, _password);
} catch (error) {
console.log('Error Signing in');
}
finally {
return {
isCommitted: error ? false : true,
message: error,
payload: user
}
}
}
I have separate file for communicating with Amplify. I am returning an object with different keys.
On running the code it shows me following warnings.
1 - Possible Unhandled Promise Rejection (id: 0):
ReferenceError: error is not defined
ReferenceError: error is not defined
2- Using an insecure random number generator, this should only happen when running in a debugger without support for crypto.getRandomValues
error is only scoped to the catch block, so when you try to use error in the finally block, it's an undeclared identifier. You have the same problem with user on the success path.
Instead, either track that information in variables or repeat the return statement.
export async function signIn(_username, _password) {
try {
const user = await Auth.signIn(_username, _password);
return {
isCommitted: true,
payload: user,
message: undefined, // if you need it, otherwise remove
};
} catch (error) {
console.log('Error Signing in');
return {
iscCommitted: false,
payload: undefined, // if you need it, otherwise remove
message: error,
};
}
}
The thing about the random number generator sounds like it's just a warning from the package you're using about the environment in which you're running the code (e.g., that it doesn't have a strong random number generator).
Side note: It can be correct to turn errors into return values like that, but more times than not it's more correct to allow the error to propagate to the caller (and perhaps to its, caller, etc.) rather than forcing every level to check a return value to see if something worked. Again, without knowing what this function is for, that may or may not apply here, but just flagging it up.

How to fix canLoad issue when we are returning an observable with 404 exception

I am trying to call an API in canLoad event for a module in my angular application,
Even though that API is not available and gives 404 in network, still my page is loading.
I wanted to avoid that situation if there is 404 then I wanted to redirect my page to some error page.
canLoad(route: Route, segments: UrlSegment[])
{
return this.http.get('testapi/getacces').pipe(map((response: boolean) => {
if (response) {
return true;
} else {
this.router.navigate(['/error']);
return false;
}
}));
}
Here If API presents then my code is working as expected but the issue is only when there is 404.
So, I am expecting a block which can handle the exception to route to an error page on 404 exception.
Try using catchError() operator which will handle your situation when error arrives instead of correct response.
See example:
canLoad(route: Route, segments: UrlSegment[]) {
return this.http.get('testapi/getacces').pipe(
map((response: boolean) => {
if (response) {
return true;
} else {
this.router.navigate(['/error']);
return false;
}
}),
catchError((error) =>
of(error).pipe(
map(() => {
this.router.navigate(['/error']);
return false;
}),
),
),
);
}
This is useful because 404 is Error response, which will not arive inside map, but will arrive inside catchError, so you can handle Error response as you wish.

MQTT.js - How to handle connection errors?

I have difficulties detecting connection errors with MQTT.js.
I'm trying to use it in an Angular service and connecting and communicating with the server seems to work fine when the server is running but client.on('error', ...) never fires.
I managed to detect errors when connecting by attaching the error callback to client.stream instead, but stream seems to be a private property since it isn't exposed in the official TypeScript definitions, so not sure if this really is the correct way to go.
But what I still don't get to work are errors when the connection is lost, none of the error handlers fire. Instead the browser console logs unhandled websocket errors.
Sample code:
import { Injectable } from '#angular/core';
import { connect, MqttClient } from 'mqtt';
import * as msgpack5 from 'msgpack5';
import { environment } from '../../environments/environment';
#Injectable()
export class MqttService {
private client: MqttClient;
private msgpack: msgpack5.MessagePack;
constructor() {
this.msgpack = msgpack5();
this.client = connect(`ws://${environment.host}:8001/mqtt`);
this.client.on('connect', () => {
console.log('connected');
this.client.subscribe('foo');
});
this.client['stream'].on('error', (error) => {
// fires when connection can't be established
// but not when an established connection is lost
console.log('stream', error);
this.client.end();
});
this.client.on('error', (error) => {
console.log('client', error); // never fires
});
this.client.on('message', (topic, payload) => {
console.log(topic, this.msgpack.decode(payload));
});
}
}
I had a very similar issue with client.on('error'.. didnt trigger on WebSocket connection error, the solution was:
client.stream.on('error', (err) => {
console.log('error', err);
client.end()
});

How to consume a Promise from a service (native script / firebase)?

I have a userService that calls firebase.login() which returns a result of type Promise<User>. It is called like this:
firebase.login( { config...
})
.then (function (result) { /* use result */},
function (error) { /* use error */ });
Elsewhere in the project, in a UI component, I need to react to the outcome of the login (i.e. success or error). I do not want to put any routing or similar logic into the user service, but rather have the other component control what happens next.
How is that done? How can another component react to it?
The component mentioned above is a class called LoginPage. It has a Login button which should start the Firebase login. The button is linked to a function (also called login()) in the LoginPage class.
XML:
<Button [text]="Sign in" class="submit-button" (tap)="login()"></Button>
login.component.ts
login() {
this._userService.login(this.user)
.then(function (data) {
/* go to next screen */
});
}
The above is obviously wrong, as the then clause will always be executed, regardless of the success or failure of the login.
Here is the login function in the userService:
#Injectable()
export class UserService {
login(user: User) {
firebase.login({
type: firebase.LoginType.PASSWORD,
email: user.email,
password: user.password
})
.then( function (result) {
console.log("Successful Login! " + JSON.stringify(result));
return result;
}, function (error) {
console.log(error);
return error;
});
}
UserService login method should return a promise to make it available for chaining:
login(user: User) {
return firebase.login(...)...
}
In the original above login error was already caught, this leaves the promise with resolution that can be either a result or an error.
The preferable way to handle errors here is to not catch the error in the service itself. We always want to know if login request was successful or not.
login(user: User) {
return firebase.login(...)
// second callback is optional if we don't need to log errors
.then( function (result) { ... }, function (error) {
console.log(error);
return firebase.Promise.reject(error);
});
}
This way an error can (and also should, Angular 2 will throw an error if there are uncaught promises) be caught and handled:
login() {
return this._userService.login(this.user)
.then(function (data) {
/* go to next screen */
})
.catch(function (error) { ... });
}
It is always preferable to return promises, at least for testing purposes.

What is the best way to deal with a fetch error in react redux?

I have one reducer for Clients, one other for AppToolbar and some others...
Now lets say that I created a fetch action to delete client, and if it fails I have code in the Clients reducer which should do some stuff, but also I want to display some global error in AppToolbar.
But the Clients and the AppToolbar reducers do not share the same part of the state and I cannot create a new action in the reducer.
So how am I suppose to show global error? Thanks
UPDATE 1:
I forget to mention that I use este devstack
UPDATE 2:
I marked Eric's answer as correct, but I have to say that solution which I am using in este is more like combination of Eric and Dan's answer...
You just have to find what fits you the best in your code...
If you want to have the concept of "global errors", you can create an errors reducer, which can listen for addError, removeError, etc... actions. Then, you can hook into your Redux state tree at state.errors and display them wherever appropriate.
There are a number of ways you could approach this, but the general idea is that global errors/messages would merit their own reducer to live completely separate from <Clients />/<AppToolbar />. Of course if either of these components needs access to errors you could pass errors down to them as a prop wherever needed.
Update: Code Example
Here is one example of what it might look like if you were to pass the "global errors" errors into your top level <App /> and conditionally render it (if there are errors present). Using react-redux's connect to hook up your <App /> component to some data.
// App.js
// Display "global errors" when they are present
function App({errors}) {
return (
<div>
{errors &&
<UserErrors errors={errors} />
}
<AppToolbar />
<Clients />
</div>
)
}
// Hook up App to be a container (react-redux)
export default connect(
state => ({
errors: state.errors,
})
)(App);
And as far as the action creator is concerned, it would dispatch (redux-thunk) success failure according to the response
export function fetchSomeResources() {
return dispatch => {
// Async action is starting...
dispatch({type: FETCH_RESOURCES});
someHttpClient.get('/resources')
// Async action succeeded...
.then(res => {
dispatch({type: FETCH_RESOURCES_SUCCESS, data: res.body});
})
// Async action failed...
.catch(err => {
// Dispatch specific "some resources failed" if needed...
dispatch({type: FETCH_RESOURCES_FAIL});
// Dispatch the generic "global errors" action
// This is what makes its way into state.errors
dispatch({type: ADD_ERROR, error: err});
});
};
}
While your reducer could simply manage an array of errors, adding/removing entries appropriately.
function errors(state = [], action) {
switch (action.type) {
case ADD_ERROR:
return state.concat([action.error]);
case REMOVE_ERROR:
return state.filter((error, i) => i !== action.index);
default:
return state;
}
}
Erik’s answer is correct but I would like to add that you don’t have to fire separate actions for adding errors. An alternative approach is to have a reducer that handles any action with an error field. This is a matter of personal choice and convention.
For example, from Redux real-world example that has error handling:
// Updates error message to notify about the failed fetches.
function errorMessage(state = null, action) {
const { type, error } = action
if (type === ActionTypes.RESET_ERROR_MESSAGE) {
return null
} else if (error) {
return error
}
return state
}
The approach I'm currently taking for a few specific errors (user input validation) is to have my sub-reducers throw an exception, catch it in my root reducer, and attach it to the action object. Then I have a redux-saga that inspects action objects for an error and update the state tree with error data in that case.
So:
function rootReducer(state, action) {
try {
// sub-reducer(s)
state = someOtherReducer(state,action);
} catch (e) {
action.error = e;
}
return state;
}
// and then in the saga, registered to take every action:
function *errorHandler(action) {
if (action.error) {
yield put(errorActionCreator(error));
}
}
And then adding the error to the state tree is as Erik describes.
I use it pretty sparingly, but it keeps me from having to duplicate logic which legitimately belongs in the reducer (so it can protect itself from an invalid state).
write custom Middleware to handle all the api related error. In this case your code will be more cleaner.
failure/ error actin type ACTION_ERROR
export default (state) => (next) => (action) => {
if(ACTION_ERROR.contains('_ERROR')){
// fire error action
store.dispatch(serviceError());
}
}
what I do is I centralize all error handling in the effect on a per effect basis
/**
* central error handling
*/
#Effect({dispatch: false})
httpErrors$: Observable<any> = this.actions$
.ofType(
EHitCountsActions.HitCountsError
).map(payload => payload)
.switchMap(error => {
return of(confirm(`There was an error accessing the server: ${error}`));
});
You can use axios HTTP client. It already has implemented Interceptors feature. You can intercept requests or responses before they are handled by then or catch.
https://github.com/mzabriskie/axios#interceptors
// Add a request interceptor
axios.interceptors.request.use(function (config) {
// Do something before request is sent
return config;
}, function (error) {
// Do something with request error
return Promise.reject(error);
});
// Add a response interceptor
axios.interceptors.response.use(function (response) {
// Do something with response data
return response;
}, function (error) {
// Do something with response error
return Promise.reject(error);
});

Categories