I'm trying to fetch some recipes over an API using ngrx and an interceptor that checks the URL to determine what kind of auth tokens that should be used. But for some reason that I have not manage to figure out I get and the following error:
ERROR TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
at subscribeTo (subscribeTo.js:41)
at subscribeToResult (subscribeToResult.js:6)
at MergeMapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapSubscriber._innerSub (mergeMap.js:70)
at MergeMapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapSubscriber._tryNext (mergeMap.js:67)
at MergeMapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapSubscriber._next (mergeMap.js:50)
at MergeMapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (Subscriber.js:54)
at Observable._subscribe (scalar.js:5)
at Observable.push../node_modules/rxjs/_esm5/internal/Observable.js.Observable._trySubscribe (Observable.js:42)
at Observable.push../node_modules/rxjs/_esm5/internal/Observable.js.Observable.subscribe (Observable.js:28)
at MergeMapOperator.push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapOperator.call (mergeMap.js:28)
Below is where I try to dispatch the action when my component is initiated:
constructor(private router: Router,
private route: ActivatedRoute,
private store: Store<fromRecipe.FeatureState>) { }
ngOnInit() {
this.recipeState = this.store.select('recipes');
this.store.dispatch(new RecipeActions.FetchRecipesFromApi());
}
This is the effect action that gets called:
@Effect()
recipesFetchFromAPI = this.actions$
.ofType(RecipeActions.FETCH_RECIPES_FROM_API)
.pipe(switchMap((action: RecipeActions.FetchRecipesFromApi) => {
return this.httpClient.get<ApiSearch>('https://api.edamam.com/search')
}),
map(
(searchResult) => {
return {
type: RecipeActions.SET_RECIPES,
payload: searchResult.hits
}
}
)
);
This is my interceptor that checks what url the request is from.
intercept(req: HttpRequest<any>, next: HttpHandler) : Observable<HttpEvent<any>>{
if(req.url == 'https://ng-recipe-book-55fbc.firebaseio.com/recipes.json'){
return this.store.select('auth')
.pipe(
take(1),
switchMap((authState: fromAuth.State) => {
const clonedReq = req.clone({params: req.params.set('auth', authState.token)});
return next.handle(clonedReq);
})
);
} else if (req.url == 'https://api.edamam.com/search?q=chicken') {
const clonedReq = req.clone({params: req.params.set('app_id', '123').set('app_key', '123')});
return next.handle(clonedReq);
}
}
My other actions, reducers and effects are working but this one. I have browsed the forum but have not managed to find a solution for this perticular problem. Does anyone have an idea of what is causing this? I would happily provide more code/information if that's needed.
My guess (you haven't pinpointed the problem area) is that the HTTP response is not 2xx. You are not handling error responses and so your effect will disable itself and never fire again. Here's how you should be handling errors:
@Effect()
allFiltersRequested$ = this.actions$.pipe(
ofType<AllFiltersRequestedAction>(FiltersActionTypes.AllFiltersRequested),
mergeMap(() =>
// essential to catchError else an HTTP error response will disable this effect
this.simService.getAllFilters().pipe(
catchError(() => {
return of({})
})
)
),
map((allFilters) => new AllFiltersLoadedAction(allFilters))
)
Whatever you return in the return of statement will be passed to map on failure. The effect also will not disable itself. This is the approach that Udemy promotes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With