Compojure with configurable base route - clojure

I am working with Clojure, Ring and Compojure for some time now, but I am still fairly new.
What I need to know is how to make a configurable base route, for example:
/:base-route
/:base-route/user
/:base-route/settings
/:base-route can be different (api, company, stuff...) and will depend on an internal check. What I can't do is create a universal check for all routes to see if /:base-route has the appropriate value. For example /:base-route is configured to be /api, but the user tries /company/user -> the response must be 404.

Ok, so the way to do it is with a regular expression and a context:
(defroutes routes
(context ["/:base-route" :base-route (re-pattern base-route)] [base-route]
(GET "/user" [] (str "base: " base-route " user"))
(GET "/settings" [] (str "base: " base-route " settings"))))

Related

Clojure, re-graph fetched data from graphql successfully, but callback didn't activate

So I use re-graph version 0.1.11 and I try fetching data from the endpoint. After fetching data, I checked network tab in the browser and I found the expected data after that it should activate my callback function, but it doesn't seem to work (but sometimes it works and after refreshing the page a few times it doesn't work again). Here is the code.
;; how I init re-graph
(rf/dispatch [::re-graph/init
::conf/graphql-client-name
{:ws-url url
:http-url url
:ws-reconnect-timeout 500
:resume-subscriptions? true}])
(re-frame.core/reg-event-fx
::fetch-expected-data
(fn [cofx event]
(let [app-db (:db cofx)
some-params (-> event second (cljs.core/js->clj :keywordize-keys true))
token (-> app-db (lens/get-in (auth-db/lens-token :group-level-x)))]
(re-frame.core/dispatch
[:re-graph.core/query
::conf/graphql-client-name
"query findExpectedData($query: FetchExpectedDataInput!, $token: String!) {
findExpectedData(query: $query, token: $token){
value1
value2
...
}
}"
{:query some-params
:token token}
;; this is where the problem occurs
;; even though i found the data in the network tab, but
;; this callback doesn't seem to work (sometimes it works sometimes it doens't)
[::fetched-data-completed]]))))
(re-frame.core/reg-event-fx
::fetched-data-completed
(fn [cofx [_ {:keys [data errors] :as payload}]]
(let [app-db (:db cofx)
error-message (-> errors :errors first :message)]
(if (or (nil? errors) (empty? errors))
(do (bla bla when success))
(pr error-message)))))
I'm stuck with this problem for a few months. maybe because I fetch a lot of data at the same time? or could be something else anyone knows?. By the way the actual code I use defmacro, but it works the same way as the above code.
So I managed to find the answer to my own question. It seems like app-db has not been initialized properly so I fixed that problem and everything works fine. hope it helps someone who struggle with this problem.

Clojure , how to pass correct param into function

I'm newbee in Clojure world. My pet project is writing of kafka consumer / producer. There a lot of topic in www ,but I've faced with misunderstanding.
There is a code
(ns producer
(:require [clojure.tools.logging :as log])
(:import (java.util Properties)
(org.apache.kafka.common.serialization StringSerializer)
(org.apache.kafka.clients.producer KafkaProducer ProducerRecord))
(:gen-class))
(defn create-kafka-producer [server]
(let [producer-props {
"value.serializer" StringSerializer
"key.serializer" StringSerializer
"bootstrap.servers" server }]
(KafkaProducer. producer-props)))
(defn send-single-message [producer topic-name record]
(.send producer (ProducerRecord. topic-name (str "Value: " (.value record)))))
(defn -main []
(def svr "localhost:8084")
(def producer (create-kafka-producer svr))
(send-single-message producer "Test msg"))
I want just pass some msg into kafka through send-single-message function. But as you see in code example is using (.value record) and when I'm trying to pass the "Test msg" string it crashed and show the followed error
Exception in thread "main" java.lang.IllegalArgumentException: No matching field found: value for class java.lang.String
I understand that is because I've pass string object, that has no .value
So, how is it possible to solve that issue? Thanks in advance
p.s. I've tried to pass other structure, but no results or different errors
As you noted, the error is because you're attempting to get the value field of the passed object, but you're passing in a String which doesn't have a value field.
Checking that ProducerRecord constructor signature, it takes a generic argument of type V (which is just an Object as far as Clojure is concerned). I'd just pass the String directly and omit the value field access.

Cannot use defroutes macro from compojure

When running this code :
(:use 'compojure.core)
(keys (ns-publics 'compojure.core))
(defroutes app-routes
(GET "/" [] "Hello World")
(route/resources "/")
(route/not-found "Not Found"))
I got this message:
CompilerException java.lang.RuntimeException: Unable to resolve symbol: defroutes in this context, compiling:(restful_clojure\routes.clj:5:1)
but when I run:
(keys (ns-publics 'compojure.core))
it shows that macro is defined:
(defroutes PUT POST routing routes make-route let-routes DELETE ANY let-request GET HEAD PATCH context OPTIONS)
Clojure has methods require, import, refer, and use. These are for working with different namespaces.
:use is a Keyword, which can behave like a function (in your example it should return nil), but does not do what you want.
The confusion likely arises from the fact that inside the ns macro, you can 'embed' the behavior of these functions using the corresponding keywords.
For more reading on namespaces, see this link.

Clojure - avoid duplicated code with monger requests

I am using Clojure and Monger
It works fine, and I group functions by the collection they relate to.
Therefore, every file begins like this :
(ns img-cli.model.mycollectionname
(:require [monger.core :as mg]
[monger.collection :as mc]
[edn-config.core :refer [env]])
(:import [com.mongodb MongoOptions ServerAddress DB WriteConcern]
[org.bson.types ObjectId]))
(def config (get-in env [:mongo]))
;; using MongoOptions allows fine-tuning connection parameters,
;; like automatic reconnection (highly recommended for production
;; environment)
(def ^MongoOptions opts (mg/mongo-options { :threads-allowed-to-block-for-connection-multiplier 300}))
(def ^ServerAddress sa (mg/server-address (:url config) (:port config)))
(def conn (mg/connect sa opts))
(def db (mg/get-db conn (:db config)))
(def collection-name "asset")
;; I have to write one like this every time
(defn find-one-as-map
"fetch asset by Id"
[^String id]
(mc/find-one-as-map db collection-name {:_id (ObjectId. id)}))
Code duplication has of course several disadvantages in itself.
Also I'm not sure if connections are properly pooled afterwards ?
How can I avoid doing this ?
I sense I could pass an additional "db" parameter to each function, but then where would it come from ?
If I create the db connection in the "entry" file of my program, then how could it be passed to every function from there ?
For instance let's says I have Compojure routes in different files :
;; in the main handler file
(def db ...) ;; if I move the previous db configuration
;; in here, it could be the only place where this is set
;; importing Compojure routes from different files
(defroutes routes-from-file1
routes-from-file2...)
Let's say that some functions called from some of the routes in "file2" need access to the db, how can I pass this variable to them ?
I also have a lot of repetitive code afterwards, for instance to get data by Id for every collection...
I feel this could be simplified, but I'm not sure how.
Just refer to it by its namespace
(ns foo
(:require [handler :as h]))
(println h/db)

Why does the order of Ring middleware need to be reversed?

I'm writing some middleware for Ring and I'm really confused as to why I have to reverse the order of the middleware.
I've found this blog post but it doesn't explain why I have to reverse it.
Here's a quick excerpt from the blog post:
(def app
(wrap-keyword-params (wrap-params my-handler)))
The response would be:
{; Trimmed for brevity
:params {"my_param" "54"}}
Note that the wrap keyword params didn't get called on it because the params hash didn't exist yet. But when you reverse the order of the middleware like so:
(def app
(wrap-params (wrap-keyword-params my-handler)))
{; Trimmed for brevity
:params {:my_param "54"}}
It works.
Could somebody please explain why you have to reverse the order of the middleware?
It helps to visualize what middleware actually is.
(defn middleware [handler]
(fn [request]
;; ...
;; Do something to the request before sending it down the chain.
;; ...
(let [response (handler request)]
;; ...
;; Do something to the response that's coming back up the chain.
;; ...
response)))
That right there was pretty much the a-ha moment for me.
What's confusing at first glance is that middleware isn't applied to the request, which is what you're thinking of.
Recall that a Ring app is just a function that takes a request and returns a response (which means it's a handler):
((fn [request] {:status 200, ...}) request) ;=> response
Let's zoom out a little bit. We get another handler:
((GET "/" [] "Hello") request) ;=> response
Let's zoom out a little more. We find the my-routes handler:
(my-routes request) ;=> response
Well, what if you wanted to do something before sending the request to the my-routes handler? You can wrap it with another handler.
((fn [req] (println "Request came in!") (my-routes req)) request) ;=> response
That's a little hard to read, so let's break out for clarity. We can define a function that returns that handler. Middleware are functions that take a handler and wrap it another handler. It doesn't return a response. It returns a handler that can return a response.
(defn println-middleware [wrapped-func]
(fn [req]
(println "Request came in!")
(wrapped-func req)))
((println-middleware my-route) request) ;=> response
And if we need to do something before even println-middleware gets the request, then we can wrap it again:
((outer-middleware (println-middleware my-routes)) request) ;=> response
The key is that my-routes, just like your my-handler, is the only named function that actually takes the request as an argument.
One final demonstration:
(handler3 (handler2 (handler1 request))) ;=> response
((middleware1 (middleware2 (middleware3 handler1))) request) ;=> response
I write so much because I can sympathize. But scroll back up to my first middleware example and hopefully it makes more sense.
The ring middleware is a series of functions which when stacked up return a handler function.
The section of the article that answers your question:
In case of Ring wrappers, typically we have “before” decorators that
perform some preparations before calling the “real” business function.
Since they are higher order functions and not direct function calls,
they are applied in reversed order. If one depends on the other, the
dependent one needs to be on the “inside”.
Here is a contrived example:
(let [post-wrap (fn [handler]
(fn [request]
(str (handler request) ", post-wrapped")))
pre-wrap (fn [handler]
(fn [request]
(handler (str request ", pre-wrapped"))))
around (fn [handler]
(fn [request]
(str (handler (str request ", pre-around")) ", post-around")))
handler (-> (pre-wrap identity)
post-wrap
around)]
(println (handler "(this was the input)")))
This prints and returns:
(this was the input), pre-around, pre-wrapped, post-wrapped, post-around
nil
As you may know the ring app is actually just a function that receives a request map and returns a response map.
In the first case the order in which the functions are applied is this:
request -> [wrap-keyword-params -> wrap-params -> my-handler] -> response
wrap-keyword-params looks for the key :params in the request but it's not there since wrap-params is the one who adds that key based on the "urlencoded parameters from the query string and form body".
When you invert the order of those two:
request -> [wrap-params -> wrap-keyword-params -> my-handler] -> response
You get the desired result since once the request gets to wrap-keyword-params, wrap-params has already added the corresponding keys.
The answer by danneu is nice, but it only really "clicked" for me after I visualized it in code to see how the chaining of middleware really looks like without the "->" threading macro magic (here's a link if you're not familiar with it). This is what I ended up with:
Let's say you have a request handler that looks like this:
(def amazing-handler
(-> #'some-amazing-fn
some-mware
another-mware
one-more-mware))
^^ The above handler, written without using a threading macro, would look like this (and I'm extending the indentation on purpose, so it is visually easier to understand which request belongs to which handler):
(def amazing-handler
(one-more-mware
(another-mware
((some-mware #'some-amazing-fn) request-from-another-mware)
request-from-one-more-mware)
original-request))
^^ The above is a style of code that requires us to read it from inside out (which sometimes is hard to follow), the threading macros (-> and ->>) allow us to read code in a natural left-to-right way, but it requires understanding on our part of how exactly it allows us to compose code in this "natural" way behind the scene.
Here's a more complete example:
;; For reference: this is how the end result of the entire "threading" looks like:
;; (((#'some-amazing-fn req-from-up-passed-down) req-from-up-passed-down) original-request)
(defn some-amazing-fn [req] ;; this "req" is the one that will get passed to this function from "some-mware"
(println "this is the final destination of the req", req)
(ring.util.http-response/ok {:body "some funny response"}))
(defn one-more-mware [some-argument] ;; the "some-argument" in this case is (another-mware (some-mware #'some-amazing-fn))
(fn [req] ;; the "req" here is the original request generated by the ring adaptors and passed to this chain of middleware
(println "|--> from fn inside one-more-mware")
(some-argument req))) ;; here we provide the another-mware with the request that it will then pass down the chain of middleware, you can imagine that chain, at this point in time, to look like this:
;; ((another-mware (some-mware #'some-amazing-fn)) req)
(defn another-mware [dunno-something] ;; the "dunno-something" in this case is (some-mware #'some-amazing-fn)
(fn [req] ;; the "req" here is passed from one-more-mware function
(println "|--> from fn inside another-mware")
(dunno-something req))) ;; here we are passing the "req" down the line to the (some-mware #'some-amazing-fn), so the entire thing behind the scenes, at this point in time, looks like this:
;; ((some-mware #'some-amazing-fn) req)
(defn some-mware [some-handler] ;; the "some-handler" arg here refers to #'some-amazing-fn
(fn [req] ;; the "req" here is passed to this function from another-mware function
(println "|--> from fn inside some-mware")
(some-handler req))) ;; here is where we are passing a "req" argument to the #'some-amazing-fn, so behind the scenes it could be thought of as looking like this:
;; (#'some-amazing-fn req)
(def amazing-handler
(-> #'some-amazing-fn
some-mware
another-mware
one-more-mware))
;; |--> from fn inside one-more-mware
;; |--> from fn inside another-mware
;; |--> from fn inside some-mware
;; |--> this is the final destination of the req {.. .. ..}