how to debug the ring session store? - clojure

I've defined an app and wish to be able to print out all the values contained in session store is there a good way to do this?
(def app
(-> #'handler
(ring.middleware.stacktrace/wrap-stacktrace)
(ring.middleware.session/wrap-session)))

You can specify the session store for wrap-session to use:
(def all-the-sessions (atom {}))
(def app
(-> #'handler
(ring.middleware.stacktrace/wrap-stacktrace)
(ring.middleware.session/wrap-session {:store (ring.middleware.session.memory/memory-store all-the-sessions)))
Now you can inspect the all-the-sessions atom.

Related

Implementing a login system with re-frame

I am new to re-frame and not quite sure how to build a user authentication/authorization system with it.
From what I gathered I should create an auth interceptor and place my auth logic inside :before section then inject the interceptor into every events reg-event-db and reg-event-fx that I want to protect.
Am I on the right track?
Not sure if my solution is particularly idiomatic, but I used something like the following in one of my projects. Consider it a Works For Me.
Create a map for the ajax request with a special value for error cases (ignore the context-uri function):
(defn xhrio-map [method path format success-event]
{:method method
:uri (context-uri path)
:timeout 5000
:response-format format
:on-success [success-event]
:on-failure [::ajax-failure]})
Then I use an fx handler for the failure (this is a bit more complicated as it also handles a loading indicator):
(rf/reg-event-fx
::ajax-failure
(fn [{:keys [db]} [_ http-result]]
(if (= 403 (:status http-result))
{:db (assoc db :loading-indicator nil)
:dispatch [::logout]}
{:db (assoc db :loading-indicator nil)
:dispatch
[::error-msg (str "Error fetching from " (:uri http-result)
": " (:response http-result))]})))
The ::logout events sets the document location. This also triggers the logout in the backend.
(rf/reg-event-fx
::logout
(fn [coefx [ev]]
{::location "./logout"}))
Finally, the loading of resources works like this:
(defn load-with-indicator [db xhrio-data]
{:db (assoc db :loading-indicator true)
:http-xhrio xhrio-data})
(rf/reg-event-fx
::load-documentation
(fn [{:keys [db]} _]
(load-with-indicator
db
(xhrio-map :get "documentation/"
(ajax/json-response-format {:keywords? true})
::received-documentation))))
The :received-documentation is handled by some code which invokes the correct display functions.
This uses the day8.re-frame/http-fx and ajax.core
On the backend, I use something similar to the demo code I published over at https://github.com/ska2342/ring-routes-demo.
Hope that helps.
License of the code in this post
In addition to the default license of the StackOverflow site, I also publish these lines under the Eclipse Public License either version 1.0 or (at your option) any later version.

Breaking down the ring middleware scenario

Ring is super sleek and has some pretty sensible defaults for middleware(s).
When I made a new app through leiningen (lein) I ended up with something like this in my router/handler
(def app
(wrap-defaults app-routes site-defaults))
https://github.com/ring-clojure/ring-defaults
Now I want to add more middleware (cemerick/friend) so I can do things like authentication for logins.
So, how would I translate the above into something more reminiscent of the ring middleware "stack," like at the bottom of the page https://github.com/ring-clojure/ring-defaults/blob/master/src/ring/middleware/defaults.clj
(def app
(-> handler
(wrap-anti-forgery)
(wrap-flash)
(wrap-session)
(wrap-keyword-params)
(wrap-resource)
(wrap wrap-file)))
because ring just uses function composition for middleware you can simply wrap friend around the call to wrap defaults:
(def app
(my-additional-middleware
(wrap-defaults app-routes site-defaults)
arguments to my additional middleware))
or you can thread it (for instance when you have several middlewares):
(def app
(-> (wrap-defaults app-routes site-defaults)
(friend-stuff arg arg)
(other-middleware arg arg arg))
Getting the order of the middleware right is still up to you :-/

Clojure compojure middleware and arrow syntax

I am trying to understand compojure middlewares :
The following code is from the compojure template :
(def app
(wrap-defaults app-routes site-defaults))
Is it equivalent to the following ?
(def app
(-> app-routes
(wrap-defaults api-defaults)))
I am unsure about this since in the following code my-middleware2 is called before my-middleware1
(def app
(-> api-routes
(wrap-defaults api-defaults)
(my-middleware1)
(my-middleware2)))
You are correct:
(def app
(wrap-defaults app-routes site-defaults))
Is equivalent to:
(def app
(-> app-routes
(wrap-defaults api-defaults)))
The arrow is called the Thread-First Macro and allows you to write nested s-expressions in a linear way.
In your second example, it makes sense that my-middleware2 is called before my-middleware1 when an HTTP request comes in. You are creating a Ring Handler, not calling the middleware directly.
(def app
(-> api-routes
(wrap-defaults api-defaults)
my-middleware1
my-middleware2))
Is expanded to:
(def app
(my-middleware2 (my-middleware1 (wrap-defaults app-routes api-defaults))))
When an HTTP request comes in, my-middleware2 handles it first, does something to it (i.e. extracts the session data), and then passes it along to the next middleware until one of them returns an HTTP response.
Note: I took out the parens from (my-middleware1) and (my-middleware2). When used like that it means that my-middlware1 is a function that when called with no arguments, returns a middleware function. This might be what you wanted but is not common practice.

How to apply a ring-middleware to specific group of routes?

I have a ring middleware which does some check on request maps with the header values.
For the check I have to hit the database.
If a defroutes as a set of routes starting with acommon URI pattern.
I don't want a middleware to run for any random URL that matches the pattern before getting handled.
I only want middleware to run for a certain set of URIs that I am suing inside of defroutes only. The reason being there is a database access in the middleware which I want to avoid for 404 responses having the same pattern.
Here is comporoute, a ring handler without any macro magic, aimed at composability and extensibility.
Even though it's in early alpha state it has precise docstrings already. It has a feature called inner middleware to solve the issue you are having. You may (and should) use it only for what you need it for and leave the rest to Compojure.
Given your Compojure handler/app is called compojure:
(defn demo-middleware
"A test midleware associng :bar to :foo of request"
[handler]
(fn [request]
(handler (assoc request :foo :bar))))
(defn demo-handler [request]
(ring.util.response/response
(str "id is " (get-in request [:params :id]) " "
":foo is" (:foo request))))
(def app
(comporoute.core/router
[["/demo-with-middleware"
[demo-middleware ;; all handlers in this vector are
;; wrapped via demo-middleware
["/:id" :demo-with demo-handler]]]
["/demo-without-middleware"
["/:id" :demo-without demo-handler]]]
:page-not-found compojure)
At the shell
curl http://localhost:8080/demo-without-middleware/1234
id is 1234 :foo is
curl http://localhost:8080/demo-with-middleware/1234
id is 1234 :foo is :bar
# Everything else will be handled by compojure.
Dependency vector [comporoute "0.2.0"]

Accessing Compojure query string

I'm trying to pull a value out of the url query string however I can return what I believe is a map, however when i use the below code, it doesn't process it as expected. Can anyone advise how I access specific values in the returned querystring datastructure?
http://localhost:8080/remservice?foo=bar
(defroutes my-routes
(GET "/" [] (layout (home-view)))
(GET "/remservice*" {params :query-params} (str (:parameter params))))
You'll need to wrap your handler in compojure.handler/api or compojure.handler/site to add appropriate middleware to gain access to :query-params. This used to happen automagically in defroutes, but no longer does. Once you do that, the {params :query-params} destructuring form will cause params to be bound to {"foo" "bar"} when you hit /remservice with foo=bar as the query string.
(Or you could add in wrap-params etc. by hand -- these reside in various ring.middleware.* namespaces; see the code of compojure.handler (link to the relevant file in Compojure 1.0.1) for their names.)
E.g.
(defroutes my-routes
(GET "/remservice*" {params :query-params}
(str params)))
(def handler (-> my-routes compojure.handler/api))
; now pass #'handler to run-jetty (if that's what you're using)
If you now hit http://localhost:8080/remservice?foo=bar, you should see {"foo" "bar"} -- the textual representation of your query string parsed into a Clojure map.
In the default app for compojure 1.2.0, the querystring middleware seems included by default. You can inspect the request as such.
(GET "/" request (str request))
It should have a lot of stuff, including the params key.
{ . . . :params {:key1 "value1" :key2 "value2} . . . }
As such, you can include a standard Clojure destructuring form to access the query parameters in your response.
(GET "/" {params :params} (str params))
Your page should then look like the following.
{"key1" "value1", "key2" "value2"}
As noted in the comment by Michal above, however, the keys are converted to strings and if you'd like to access them you need to use the get function rather than the more convenient symbol lookups.
(GET "/" {params :params} (get params "key1"))
;;the response body should be "value1"
With compojure 1.6.1 HTTP-request-destructuring works for me in a such way:
add [ring/ring-defaults "0.3.2"] in :dependencies in project.clj (because compojure.handler namespace was deprecated since 1.2 in favor of the [ring-defaults])
add [ring.middleware.defaults :refer :all] in :require in your.routes.namespace
add (def site (wrap-defaults app site-defaults)) in your.routes.namespace, where app is declared via (defroutes app ...
add :ring {:handler your.routes.namespace/site} in project.clj
I had luck in compojure 1.1.5 not needing a wrapper and being able to use the :as directive
(GET "/tweet/:folder/:detail" [folder detail :as req]
(twitter-controller/tweet folder detail (-> req :params :oauth_verifier))