I'm currently using redux and redux-thunk middleware.
When it comes to controls regarding action dispatching, such as:
does the user have sufficient permissions for this action?
prompt the user to confirm his action (for destructive action)
I believe placing such controls inside async actions (thunk) is the way to go, because:
it keeps my code DRYer (many components/views could trigger the
action, whereas there is only one actionCreator for said action)
it's the last point before "something happens" in the app. Making it feel like a strategic place to make such controls.
The question(s)
I'm looking for feedback from other redux users. I'm fairly
confident of this decision, but having little feedback (and being
junior dev) makes me doubt. Is this the right way to go for
authorization controls when using redux?
What about making the authorization controller into
middleware. It would keep auth controls in a single place instead of duplicating it in every actionCreator.
Edit
When digging deeper into this possibility it quickly became challenging because middleware initially only receive (dispatch, getState) meaning that an authorization middleware would need to "know" which action is being dispatched (or which actionCreator is being used), something that required a hacky-ish setup and eventually proved un-reliable.
Other points
Yes, this is client-side. Yes, we also make server-side checks.
I know that these types of controls should NOT be in my store/reducers. They need to be pure.
I think you are good to go with your setup. Thunk is a good way for orchestrating your program-flow. There are also other Middlewares like redux-saga which is a bit more sophisticated but as far as i understand you want to do something like this (pseudo code)?
function authorizeAndTriggerAction(forUser) {
return function (dispatch) {
return authorizeUser().then(
action => dispatch(concreteAction(forUser)),
error => dispatch(notAuthorized(forPerson, error))
);
};
}
This can be done with thunk.
Related
I have a mobile app made in React Native, and I've just run into a best practice dilemma i've encountered many times while using Redux/Redux Saga. I would love if i could get someone else's thoughts on this.
For a new piece of functionality i'm implementing, i need to be able to tell how many times the app has been launched. This involves asynchronously retrieving how many times the app was previously launched from the device storage. If there's a new launch happening, i also need to add +1 to the number and store that in the device storage.
This is how i currently do it:
Dispatch appLaunched() action when app launches.
Redux Saga takes event.
Inside Saga: Retrieve how many times app was previously launched (appLaunchCount) from device storage (wait for async to finish).
Add +1 to previous appLaunchCount.
Store new appLaunchCount in device storage (wait for async to finish).
Dispatch put() with new appLaunchCount to reducer.
Update state with new appLaunchCount inside reducer.
My problem with this method is step 6. Technically any part of my app could dispatch a new app launch count to my reducer, with any integer, and the reducer would update the state just the same even though it didn't come from the saga.
My question is this: How can i protect my Reducers/Sagas/Actions so that only my saga can dispatch the action with the current appLaunchCount ?
P.S The only solution i can think of is writing my saga and reducer in the same file, and use private actions that only the saga and reducer can access. I would really hate to have to keep all that code together though.
Private actions aren't really a thing. The store is, by design, a global object. And since actions are just objects with a type property, anyone who can construct an action object of the right type can in principle dispatch an action and kick off your reducer.
What you could do is make the action have a type that makes it obvious that it's meant to be private. For example, maybe the action looks like:
{
type: '__PRIVATE_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED__'
// You could tone it down a bit from this :)
}
That of course doesn't make it actually private, but at least if someone wants to use it, it's impossible for them to not realize your intent.
If you wanted to make it more secure, perhaps you could use a symbol as the type, and therefore only anyone with access to the symbol could construct the right action. For example:
const appLaunchCount = Symbol('appLaunchCount');
// action would look like:
{
type: appLaunchCount
}
But then the issue is making sure that symbol stays hidden, and can be accessed only by those who you want to access it. Similar to one of the things you mentioned, if you have the saga/reducer in the same file, then you could make sure that other files couldn't access this symbol; but once you start exporting it it becomes harder to control.
Is possible to get which component call some action Vuex ?
I return a promise from vuex actions and take some decisions in component as set errors messages on respective fields but I would like to set on component.$validator.errors asap I receive http response (in action method)
Is that possible and a good approach ?
In Vuex when you make a call to a mutation or action you can send an object alongside your dispatch call, if you wanted to track the component which called an action you could also send that as part of the object. Better yet you could have all objects sent via Vuex extend a specific class if your using typescript. Though note that finding which component called an action or mutation is not native behavior for Vuex.
Consider the following:
try{
let out = await this.$store.dispatch('someActionHandler', {referingComponent: this.$options.name, someParam:[1,2,3]})
} catch (e){
// Lets deal with the problem
}
In here we are sending the name of the component as a parameter, so it can be checked inside our action handler or alternatively you could just pass this straight to a mutation, though I think the former is a more likely case if you plan to build logic into this.
As for if this is a good approach, the answer to that is fairly subjective, I personally don't see any problems with the above approach. Though I would think it was an anti pattern if the majority of components are never checked or the added data ends up becoming meaningless fluff passed alongside every call.
In my Angular app I'm working on notifications and I have an REST API to call for latest user's notifications. I need to call this API on few minutes since it's not really important that user gets notifications in real time (they probably won't even appear that fast). However the idea to refresh notifications on the client side is next:
When user logs in start refreshing notifications - here is the first manual call to start refreshing the API on few minutes
If user leaves app opened or is just navigating through the app then don't change timer and wait for the rest of the time
If user opens subpage where it can perform actions related to notifications and does it, then refresh notifications and reset timer
Refresh notifications until logout
I already have working code for the described procedure, but I'm somehow unsure that it's correct for what I need. Here is the code for performing calls (for manual check there is just a Subject and for stop checking there is a subscription to observable - code below is actually separated, but here is in one place because of readability):
// Subject for manual triggering
this.checkFeed = new Subject<void>();
// Call for refresh in own method
this.checkFeed.next();
// Waiting for manual refresh or triggering it on some interval after it was last triggered
this.feedSub = this.checkFeed.asObservable()
.switchMap(() => Observable.timer(0, this.interval))
.mergeMap(() => this.fetchChanges())
.distinctUntilChanged(this.compareFeed)
.subscribe(res => this.notify(res));
// Unsubscription when logging out
if (this.feedSub) this.feedSub.unsubscribe();
The part which I'm most unsure about is .switchMap(() => Observable.timer(0, this.interval)) since it needs 0 to start right away (which is ok, but still doesn't look correct at all?). So is there any better way to achieve what I described?
I also have another question how to start check for notifications from another observable - which operator should I use. As I mentioned I have call to the Subject's next in own method like this:
refreshFeed(): void {
this.checkFeed.next();
}
So when there is some other observable performing (the action when notifications should be refreshed) I need to call this one. What's the correct way to call void method when other observable has response from API? I was thinking of something like this:
someActionThatCanChangeNotifications(): Observable<any> {
return this.api.get('path/to/endpoint')
.do(() => this.feedService.refreshFeed());
}
Is this ok, or is there also any better way?
Thanks in advance for help!
So basically you have two observable.
One that you call manually:
this.checkFeed
and the interval(let's callit intervalObs):
this.intervalObs = Observable.timer(0, this.interval);
If you see it like this the easyest way is to merge you'r two source stream and then do whatever you want.
var mergedSource = Observable.merge(
this.checkFeed,
this.intervalObs)
subscription = mergedSource.subscribe(this.fetchChanges());
Maybe you need to do some more operation in between but this should give you a more readable alternative.
You can try this working plunker if you want something to play arround https://plnkr.co/edit/n4nNFEMa4YOh2KSjDpSJ?p=preview
From what I can see you've pretty much done it "correctly". As with programming in general, there are many possible (and correct) solutions to a single problem. Personally, I'd do this the same way.
I can give you some commentary on the two points you mentioned too:
.switchMap(() => Observable.timer(0, this.interval))
Observable.timer pretty much an Observable.interval with a custom timeout before the first value. Observable.timer(0, this.interval) is the correct usage.
An alternative could be Observable.just(0).concat(Observable.interval(this.interval)), which returns a value immediately and then starts the interval. I prefer the way you put however; I think it clearly states your intention: "Produce a value after 0 milliseconds, and then an interval of this.interval".
.do(() => this.feedService.refreshFeed())
I'd say this is the totally correct way of doing it. do is meant for side effects, eg. stuff that happening outside the observable.
I can say though, I wouldn't expect someActionThatCanChangeNotifications to kick off a refresh of the feed. When a function returns an observable, I would expect to return an observable that doesn't have any side effects. However, as we live in a non-perfect world, we can't always have what we want.
You can't expect every subscriber to remember to do .do(() => this.feedService.refreshFeed()), instead I'd add a notice in the doc comment for the function: "Note: The returned observable will refresh the feed on every next signal", or something of that kind.
I'm building an express app in express 4.0 (rc3), since I'm starting from scratch and in development for a while, but if there's a way to do this in 3.0, that'd be welcome too.
What I want is a set of comment REST routes that I can attach to other routes in my API. So:
/posts/:postID/comments/:commentID
/profiles/:profileID/comments/:commentID
The way I was doing it was to encapsulate the comment routes into a module, including a buildRoutes(router) function in the module.
Then I can do app.use('/api/comments', commentController.buildRoutes(express.Router())) in my main server definition, and then in my profile module's buildRoutes(router), I can do
buildRoutes = function(profileRouter)
.... build the basic CRUD routes ...
profileRouter.get('/:profileID', show)
profileRouter.use('/:profileID', commentController.buildRoutes(express.Router()))
It seems like only the .VERB methods actually replace :wildcards in the route, and not the .use one. I could always muddle through with a piece of custom middleware that goes on a /api/profiles/* and maps the appropriate URL parameters into req.fields, but I want to make sure that this is actually required.
So this wasn't particularly easy to do the way I originally intended. However, I just avoided the entire problem by reframing my buildRoutes method to accept a baseURL and a router argument. Instead of modularizing it completely, now I say, profileController.buildRoutes('/api/profiles/', router) which in turn calls commentController.buildRoutes('/api/profiles/:profileID/comments', router), and so on.
It's not terribly satisfying (I would rather encapsulate path/routing information and hide that from the controller) but it works.
Working on my first EmberJS app. The entire app requires that a user be logged in. I'm trying to wrap my head around the best way to enforce that a user is logged in now (when the page is initially loaded) and in the future (when user is logged out and there is no refresh).
I have the user authentication hooks handled - right now I have an ember-data model and associated store that connects that handles authorizing a user and creating a user "session" (using sessionStorage).
What I don't know how to do is enforce that a user is authenticated when transitioning across routes, including the initial transition in the root route. Where do I put this logic? If I have an authentication statemanager, how do I hook that in to the routes? Should I have an auth route that is outside of the root routes?
Note: let me know if this question is poorly worded or I need to explain anything better, I will be glad to do so.
Edit:
I ended up doing something that I consider a little more ember-esque, albeit possibly a messy implementation. I have an auth statemanager that stores the current user's authentication key, as well as the current state.
Whenever something needs authentication, it simply asks the authmanager for it and passes a callback function to run with the authentication key. If the user isn't logged in, it pulls up a login form, holding off the callback function until the user logs in.
Here's some select portions of the code I'm using. Needs cleaning up, and I left out some stuff. http://gist.github.com/3741751
If you need to perform a check before initial state transition, there is a special function on the Ember.Application class called deferReadiness(). The comment from the source code:
By default, the router will begin trying to translate the current URL into
application state once the browser emits the DOMContentReady event. If you
need to defer routing, you can call the application's deferReadiness() method.
Once routing can begin, call the advanceReadiness() method.
Note that at the time of writing this function is available only in ember-latest
In terms of rechecking authentication between route transitions, you can add hooks to the enter and exit methods of Ember.Route:
var redirectToLogin = function(router){
// Do your login check here.
if (!App.loggedIn) {
Ember.run.next(this, function(){
if (router.currentState.name != "login") {
router.transitionTo('root.login');
}
})
}
};
// Define the routes.
App.Router = Ember.Router.extend({
root: Ember.Route.extend({
enter: redirectToLogin,
login: Ember.Route.Extend({
route: 'login',
exit: redirectToLogin,
connectOutlets: function(router){
router.get('applicationController').connectOutlet('login');
}
}),
....
})
});
The problem with such a solution is that Ember will actually transition to the new Route (and thus load all data, etc) before then transitioning back to your login route. So that potentially exposes bits of your app you don't want them seeing any longer. However, the reality is that all of that data is still loaded in memory and accessible via the JavaScript console, so I think this is a decent solution.
Also remember that since Ember.Route.extend returns a new object, you can create your own wrapper and then reuse it throughout your app:
App.AuthenticatedRoute = Ember.Route.extend({
enter: redirectToLogin
});
App.Router = Ember.Router.extend({
root: Ember.Route.extend({
index: App.AuthenticatedRoute.extend({
...
})
})
});
If you use the above solution then you can cherry pick exactly which routes you authenticate. You can also drop the "check if they're transitioning to the login screen" check in redirectToLogin.
I put together a super simple package to manage session and auth called Ember.Session https://github.com/andrewreedy/ember-session
Please also take a look at :
http://www.embercasts.com/
There are two screencasts there about authentication.
Thanks.