3
votes

Using Angular and ngrx, I want to navigate to a route and ensure that the required data is available in the ngrx/store. I am using a ngrx/store action/effect/reducer to physically call the API. The component that the route is loading accesses the data via the store, as other parts of the system may update the data.

If data fails to load, a LOAD_FAILED action is dispatched, which could be handled in numerous ways.

Should I use a guard or a resolver? What are some other pros and cons of each approach? What have you tried, and if you had your time again, would you do it the same way? Below are some of my thoughts.

Option 1: Guard

When the route is accessed, a guard's canActivate checks to see if the data is in the store, and if not, loads it from the API, and adds it to the store . If data fails to load, canActivate will then return false (as an observable).

This approach has the downside of "loading data shouldn't be a guard's responsibility", but has the upside of preventing access if data cannot be loaded, and the router can handle the fall-through to a "not found", both of which are within the responsibilities.

Option 2: Resolver

When the route is accessed, and any other guards have allowed activation, the resolver is called. This resolver checks if the data is in the store, and if not, fires off a LOAD action, to load from the API and add to the store. Then, once the data has been loaded, the resolver returns some arbitrary data, which is discarded by the route/component, as the component uses the store. If data fails to load, something would redirect to the not found page

This approach has the downside that the resolver is not being used in a traditional sense, e.g. the data that it returns is discarded. Additionally, either the resolver needs to redirect to 404 when not found, or the LOAD_FAILED needs to redirect. This adds complexity, as there may be times when LOAD_FAILED shouldn't redirect, e.g. when a background action triggers a load. On the upside, it is the responsibility of a resolver to load data.

1
I personally would use guards and resolvers for exactly what they are. However, since you are using ngrx and don't have to worry about getting pre-fetched data from resolvers, I think you'd be okay either way.Anjil Dhamala
@AnjilDhamala, thanks for your comment. The question here is actually about which is more appropriate- a guard is meant to allow/prevent access, but in this case, "no having the data" is what we want to guard against. Resolvers are meant to fetch data, so that seems logical. If resolvers executed before guards, it would make sense to use both, but since guards execute first, I am not entirely clear as to the best approach!AndrewP

1 Answers

1
votes

I think in your case you'll be fine with either Guards or Resolvers.

I personally think Resolvers are more appropriate for pre-fetching data. I see no problem in data being discarded. You can also provide some useful information about data retrieval to the final component (if the data was only partially available, for example).

I didn't really understand what do you mean by the downside of doing redirect in the Resolver. I believe there is no such issue, you can handle redirects in Resolver as it is demonstrated in Angular guide. In the basic case of fetch failure the routing event will be canceled and the user will remain on the current page.

The only real advantage of using Guards as I see is that you are able to execute them in queue. It potentially allows you to create more generic and reusable Guard classes, where each Guard is responsible for retrieving specific bits of data. Resolvers, on the other hand, are more route-specific rather than data-specific.