Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pre- / post- actions for post-dispatch #21

Closed
ddellacosta opened this issue Mar 2, 2014 · 6 comments
Closed

pre- / post- actions for post-dispatch #21

ddellacosta opened this issue Mar 2, 2014 · 6 comments
Milestone

Comments

@ddellacosta
Copy link
Contributor

...continues discussion from IRC.

I propose to add a mechanism for performing pre-/during-/post- actions, after dispatch has happened (that is, wrapping the form in defroute).

Here is a set of proposed protocols and some usage patterns:

(defprotocol IPreRoutingAction
   (pre-routing-action [this] ...))

(defprotocol IRoutingAction
   (routing-action [this] ...))

(defprotocol IPostRoutingAction
   (routing-action [this] ...))

By default, you would continue to call defroute as now:

(defroute "/myroute/:id" [id]
  ;; ...do stuff...)

But, you could then also do something like this (mimicking Om usage patterns):

(defroute "/myroute/:id" [id]
  (reify
    IPreRoutingAction
    (pre-routing-action [this]
     ;; ...)
    IRoutingAction
    (routing-action [this]
     ;; ... the stuff from before ...)))

A more concrete use-case (and why I was proposing it in the first place):

(deftype Page []
  IPreRoutingAction
  (pre-routing-action [this page-args]
    (load-page! page-args))
  IRoutingAction
  (routing-action [this page-args]
    (load-header! (:name page-args)))

(defroute "/myroute/:id" [id]
  (Page. id {:name "foo"}))

This would eliminate a lot of boilerplate and satisfy the needs of many developers building complex one-page apps in CLJS (as we are).

Also proposed by noprompt: IWillNavigate/INavigate/IDidNavigate protocols. Should pre-dispatch protocols be allowed in arguments to defroute? Etc.

Okay, this is just the first proposal--let me know what you think.

@gf3 gf3 added the enhancement label Mar 3, 2014
@gf3 gf3 added this to the v2.0.0 milestone Mar 3, 2014
@gf3
Copy link
Collaborator

gf3 commented Mar 3, 2014

Oooh—I quite like this idea.

Do you think it'd also be useful to support pre/post actions for an entire route collection?

@noprompt
Copy link
Collaborator

noprompt commented Mar 4, 2014

I like this idea too but the more I think about it the more I wonder if it should be packaged with Secretary. Since secretary/dispatch! returns a value it seems like this architecture could be implemented by the library consumer without help from Secretary.

(let [o (secretary/dispatch! "/some/route")]
  (cond
    (satisifies? IRoutePreAction x)
    (route-pre-action x))
    ...
    :else o)

I still think this is a great idea but let's have a handful of solid use cases before deciding whether or not to add it.

Edit: Fix weird grammar.

@ddellacosta
Copy link
Contributor Author

It's important to note that what I'm proposing explicitly happens post routing (although I do ask in my original comment whether or not this could/should be extended to pre-routing operations too). The use cases for this depend on the de-structured route parameters being available to the pre-/during/post- route actions as I described above.

Here's another use-case as an example--you could use this to filter post routing, based on routing args:

(deftype FilterBadString [filter-str
  IPreRoutingAction
  (pre-routing-action [this str]
    (when (re-find (re-pattern filter-str) str)
      (secretary/dispatch! "/safe-page"))))

(defroute "/search/:str" [str]
    (FilterBadString. "bad!")
    ;; ... do stuff ...
    )

In general, I could certain do this as I do now with this kind of code:

(defn pre [args] ;; do stuff )
(defn post [args] ;; do stuff )
(defn wrap-pre-and-post [args f]
  (pre args)
  (f)
  (post args))

(defroute "/myroute/:id" [id]
   (wrap-pre-and-post
      (fn [id]
         ;; do stuff)))

...and this is what I have to do now. It's okay, it works, but it requires customization of arguments and is not particularly smart. So the next step I was going to make was to basically re-implement defroute myself to essentially do what I'm describing in this issue. I certainly have no problem doing it separately but it seemed like a common enough pattern that others could make use of it. Whether or not it should be a part of secretary or not, I'm not sure...up to you guys.

@ddellacosta
Copy link
Contributor Author

@gf3 Sorry, I didn't answer your question:

Do you think it'd also be useful to support pre/post actions for an entire route collection?

Seems like the answer is yes if there was a route collection helper that this could fit into. This depends on defroute taking advantage of the protocols, so whatever would allow you to define a route collection (defroutes?) would have to be aware of the protocols as well. But seems like you may want this for a group of route too--for example, if you have a section of your site with the same headers or something, this could help you easily set that up.

@ddellacosta
Copy link
Contributor Author

I had to implement this for our own project--here's the gist.

@ddellacosta
Copy link
Contributor Author

I'm withdrawing this issue--I'm glad we waited on it. Having used our own version of this in production for months, I realize that it doesn't really solve any problems that can't be solved in a simpler fashion otherwise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants