I'm developing a Clojure webnoir app and I need to construct a callback url (for Twitter oauth) that is different in dev-mode than it is in production mode. In dev-mode it needs to be localhost:8080/smth and on production (heroku) obviously something else like http://smooth-lightning-xxxx.herokuapp.com/smth. How do I get the localhost:8080 part programmatically in a defpage?
I haven't tried it, but I think this should work
(ns your-namespace
(:require noir.request))
and then in defpage:
(let [server-name (:server-name (noir.request/ring-request))]
...)
You can also looke at noir middleware if you need to tweak requests and responses a lot.
In the end I solved it using this, inside a defpage, with noir.request required as request:
((:headers (request/ring-request)) "host")
Related
I have been using Clojure, ClojureScript, lein, shadow-cljs, Emacs, and CIDER to work on a Clojure/ClojureScript dynamic web app project.
Usually, I build the project executing command cider-jack-in-cljs in Emacs, choosing shadow-cljs, then shadow for REPL type, and, finally, app for building option.
It works fine. I can watch changes on the UI on localhost:3005.
There is something weird though that I do not understand (take into consideration that I am new to the Clojure stack).
On the REPL I can do:
cljs.user> #(re-frame.core/subscribe [:the-selections])
{:firm "cb08795f-378b-4eb0-9404-ad83b83a8474",
:active-client "Random-client",
:active-atb "c6193c35-bf91-4711-8523-d905bd7f0a03"}
The keywords inserted by me and retrieved by the REPL are related to the project.
My doubt is about the fact that this only works if the browser is in a specific page (address). Authentication here is not relevant.
On http://localhost:3005/link/random-numbers-asidadbsadkfbajhksdbf9283492374, it works:
cljs.user> #(re-frame.core/subscribe [:the-selections])
{:firm "cb08795f-378b-4eb0-9404-ad83b83a8474",
:active-client "Random-client",
:active-atb "c6193c35-bf91-4711-8523-d905bd7f0a03"}
But, if change the address bar on the Chrome browser to another valid path being properly rendered by the browser: http://localhost:3005/another-path.
And if try the same command, surprisingly the REPL retrieves nil:
cljs.user> #(re-frame.core/subscribe [:the-selections])
nil
Even after authentication and even if the browser address is inside the home page, the command above does not work. It only works after the address is on a specific page.
In addition, based on #ThomasHeller's comment, it seems to be relevant to post how :the-selections is defined. I am not sure this is the root of the definition, but it is my best bet:
(rf/reg-sub
:the-selections
;; Only returns something if all :firm, :active-client, and
;; :active-atb are present. :raw-selections defined in
;; selections.cljs omits validation if (rarely) needed. selections
;; are only stored locally in re-frame's app-db, not in firebase,
;; like :the-client and :the-atb. Minor selections components which
;; are not part of the validation are :active-account and :active-je
(fn [_q _d]
(rf/subscribe [:raw-selections]))
(fn [selections _q]
(tc-selections/valid-selections selections)))
This behavior intrigues me. Isn't a re-frame.core/subscribe an interface to the database?
According to re-frame's documentation:
When a View Function uses a subscription, like this (subscribe [:something :needed]), the sub-graph of nodes needed to service that subscription is created. The necessary sub-graph will "grow backwards" from the View Function all the way to app-db.
If so, why should the address bar on the browser matter after proper build and authentication?
This is impossible to answer without knowing how :the-selections is defined.
However, a guess would be that the value is provided by the "router". It basically takes the URL and puts some data related to it into the app-db. In case of URIs starting with /link it may be creating the necessary data, while others don't.
I'm trying to understand when the ring anti-forgery token is generated or inserted in an HTML page. I'm using Compojure / ring / hiccup but I take it my question is really about ring. I don't have any problem per se: I just want to know when and how the anti-forgery token is "injected".
The anti-forgery-field function from ring.util.anti-forgery is implemented like this:
(html (hidden-field "__anti-forgery-token" *anti-forgery-token*)
If I call this function at a REPL I get:
REPL> (println (anti-forgery-field))
<input id="__anti-forgery-token" name="__anti-forgery-token" type="hidden" value="Unbound: #'ring.middleware.anti-forgery/*anti-forgery-token*" />
Still at the REPL, if I try to get this var I get the same "unbound" variable:
> ring.middleware.anti-forgery/*anti-forgery-token*
=> #object[clojure.lang.Var$Unbound 0x1eae055 "Unbound: #'ring.middleware.anti-forgery/*anti-forgery-token*"]
What I don't understand is what that "Unbound" value is nor when it is transformed (by ring?) into an actual token delivered. And I especially don't understand how several users connecting to the website do get, each, a different token (per session).
Is that variable always "unbound"? When/how does it become "bound" (if it does?)?
Also, if I've got the ring session ID (say "ring-session=310678be-9ef6-41a7-a12a-b2417de4a79f"), how can I see, at the Clojure REPL (on the server side), the corresponding anti-forgery token's value?
It is bound only in the context (dynamic environment, the current stack, if you will) of the individual request. Think of it as a thread-local variable/binding. You are not in the context of a request while looking at your application state from a REPL.
It must be this way, because it has to be a different value for each user. You'd simulate similar behaviour through an explicit lookup call, if you were working in an environment that does not allow this kind of control of the dynamic environment.
The binding to the right session value is established in the middleware during the request, currently here:
https://github.com/weavejester/ring-anti-forgery/blob/master/src/ring/middleware/anti_forgery.clj#L67
(binding [*anti-forgery-token* (session-token request)]
;; ...
)
I'm new to Clojure, and trying to get a few simple web routes set up. I want the routes to reload all associated code in development, but not in production.
I was only able to get this to work using the var's for the routes, not the actual symbols. Can someone explain if I'm doing this wrong? If not, why is the var required?
(def app-handler
(let [formats [:json-kw :edn :yaml-kw :yaml-in-html :transit-json :transit-msgpack]
wrapped-api (wrap-restful-format #'routes/api-routes :formats formats)
combined-routes (compojure.core/routes wrapped-api #'routes/html-routes)
with-defaults (wrap-defaults combined-routes api-defaults)]
(if (is-dev?)
; Development
(wrap-reload with-defaults)
; Production
with-defaults)))
(Note #'routes/api-routes and #'routes/html-routes above).
In a manner described in more detail in another answer, the server ends up capturing your route functions when they are passed in, and if you provide the var, this will ensure that the server uses any updated definitions.
This is considered the normal way to provide your route or handler function during development, so that you can see updated definitions without having to restart your web server process.
I'm confused by how calls with carmine should be done. I found the wcar macro described in carmine's docs:
(defmacro wcar [& body] `(car/with-conn pool spec-server1 ~#body))
Do I really have to call wcar every time I want to talk to redis in addition to the redis command? Or can I just call it once at the beginning? If so how?
This is what some code with tavisrudd's redis library looked like (from my toy url shortener project's testsuite):
(deftest test_shorten_doesnt_exist_create_new_next
(redis/with-server test-server
(redis/set "url_counter" 51)
(shorten test-url)
(is (= "1g" (redis/get (str "urls|" test-url))))
(is (= test-url (redis/get "shorts|1g")))))
And now I can only get it working with carmine by writing it like this:
(deftest test_shorten_doesnt_exist_create_new_next
(wcar (car/set "url_counter" 51))
(shorten test-url)
(is (= "1g" (wcar (car/get (str "urls|" test-url)))))
(is (= test-url (wcar (car/get "shorts|1g")))))
So what's the right way of using it and what underlying concept am I not getting?
Dan's explanation is correct.
Carmine uses response pipelining by default, whereas redis-clojure requires you to ask for pipelining when you want it (using the pipeline macro).
The main reason you'd want pipelining is for performance. Redis is so fast that the bottleneck in using it is often the time it takes for the request+response to travel over the network.
Clojure destructuring provides a convenient way of dealing with the pipelined response, but it does require writing your code differently to redis-clojure. The way I'd write your example is something like this (I'm assuming your shorten fn has side effects and needs to be called before the GETs):
(deftest test_shorten_doesnt_exist_create_new_next
(wcar (car/set "url_counter" 51))
(shorten test-url)
(let [[response1 response2] (wcar (car/get (str "urls|" test-url))
(car/get "shorts|1g"))]
(is (= "1g" response1))
(is (= test-url response2))))
So we're sending the first (SET) request to Redis and waiting for the reply (I'm not certain if that's actually necessary here). We then send the next two (GET) requests at once, allow Redis to queue the responses, then receive them all back at once as a vector that we'll destructure.
At first this may seem like unnecessary extra effort because it requires you to be explicit about when to receive queued responses, but it brings a lot of benefits including performance, clarity, and composable commands.
I'd check out Touchstone on GitHub if you're looking for an example of what I'd consider idiomatic Carmine use (just search for the wcar calls). (Sorry, SO is preventing me from including another link).
Otherwise just pop me an email (or file a GitHub issue) if you have any other questions.
Don't worry, you're using it the correct way already.
The Redis request functions (such as the get and set that you're using above) are all routed through another function send-request! that relies on a dynamically bound *context* to provide the connection. Attempting to call any of these Redis commands without that context will fail with a "no context" error. The with-conn macro (used in wcar) sets that context and provides the connection.
The wcar macro is then just a thin wrapper around with-conn making the assumption that you will be using the same connection details for all Redis requests.
So far this is all very similar to how Tavis Rudd's redis-clojure works.
So, the question now is why does Carmine need multiple wcar's when Redis-Clojure only required a single with-server?
And the answer is, it doesn't. Apart from sometimes, when it does. Carmine's with-conn uses Redis's "Pipelining" to send multiple requests with the same connection and then package the responses together in a vector. The example from the README shows this in action.
(wcar (car/ping)
(car/set "foo" "bar")
(car/get "foo"))
=> ["PONG" "OK" "bar"]
Here you will see that ping, set and get are only concerned with sending the request, leaving the receiving of response up to wcar. This precludes asserts (or any result access) from inside of wcar and leads to the separation of requests and multiple wcar calls that you have.
I'm working with Noir and I can't figure out how to pass information to the views.
Right now I have a ref in proj.core/my-ref which is updated in a worker thread.
I need to access the ref's value from a view created via defpage located at proj.views.my-view.
What would be the idiomatic way of sharing this ref?
I was thinking of passing it in a closure somehow but I don't see how that would work with the way noir pulls in the views
ie
(noir.server/load-views-ns 'proj.views)
Move the ref to it's own namespace and then just require proj.core in your proj.views, like:
(ns proj.views
(:require proj.model))
(defpage "/foo" [] (#proj.model/my-ref)