Accessing Compojure query string - clojure

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))

Related

How do I obtain all of plain POST form parameters in compojure.api.sweet?

I have a route for which I have to get all of parameters from body.
I have no choice because it will be called from a third party system so I have to work with simple tools. I also don't have complete control of the data that is passed and I need everything anyway. I need every field but I don't know what those are.
One of the solutions would be to cherry-pick all fields that can be submitted and use optional parameters, but that's not ideal because I'll have to test that by hand for all request types.
And as I figured out there are at least 30 different submitted fields in my request which are needed to be concatenated for HMAC request validation. You can guess how my handler looks like... (Hint: {Field :- s/Str ""})
And I have one more request that is going to be at least this big but different. And I plan more in the future. Oof.
So: How do I get all of the submitted body parameters without any deserialization?
HTTP Body string, parameter map or InputStream are completely acceptable solutions. At this point anything is better than specifying all of that by hand. (VIM macros -- thanks for all your help)
My code:
(ns api.compojure-api
(:require [compojure.api.sweet :refer :all]
[schema.core :as s]
[ring.util.http-response :refer :all]
[ring.middleware.params]
[muuntaja.middleware]))
(def app
(api
(context "/something" []
(POST "/api/:variable" req
:middleware [;;ring.middleware.params/wrap-params ;; This does nothing
;;muuntaja.middleware/wrap-params ;; This does nothing
(fn [handler]
(fn
([request]
(println "request" request) ;; This prints the request but params are not there, they are not deserialized
(handler request))
([request respond raise]
(println "request" request)
(handler request respond raise))))]
;; :body-params [some-body-param :- s/Str] ;; This works if I know the fields. But I don't want to know or specify.
;; :coercion nil ;; stops coercing the output, but I need to not coerce the input into String or Object too.
(println (:params req)) ;; this prints only value from path (`:variable`), but not from body.
(ok))
)))
I've tried multiple things but nothing worked so far.
I can't copy the methods from compojure examples that wrap whole routes because compojure.api.sweet is different from plain compojure.
Versions:
[org.clojure/clojure "1.10.1"]
[metosin/compojure-api "1.1.13"]
[ring/ring-core "1.8.0"]
[metosin/muuntaja "0.6.6"]
[metosin/ring-http-response "0.9.1"]
All of these solutions return nil:
How to get all the params of a POST request with Compojure
muuntaja.middleware/wrap-format middleware (and together with wrap-params in both orders) also doesn't do anything.
I also tried to print (slurp (:body req)) and ring.util.request/body-string but it's empty. In fact this is the output of (println (:body req)):
#object[org.eclipse.jetty.server.HttpInputOverHTTP 0x12335807 HttpInputOverHTTP#12335807[c=0,q=0,[0]=null,s=EOF]]
Which says that parameter s=EOF. But I've set the content type to form and added some data to the body.

Finding Matched Path in Clojure Web Service

I hope I can explain this in such a way that it makes sense!
I'm using Liberator to prototype some web services that I need to expose to clients and have route(s) defined like so:
(defroutes fish
(context "/fish"
[]
(ANY "/cod/:id/count"
[id]
(cod-fish id))))
(def handler
(-> fish
wrap-params
path-wrapper))
The intention of path-wrapper is to output some information about the matched path. It currently looks like so:
(defn path-wrapper
[handler]
(fn [request]
(println "in" (:request-method request) (:uri request))
(let [response (handler request)]
(println "out")
response)))
This prints out what you'd expect:
in :get /fish/cod/123/count
out
However, what I'd like it to print out is:
in :get /fish/cod/:id/count
out
That is, the path that matched rather than the URI that matched it.
I'm almost certain that the answer is in Clout somewhere but I don't seem able to find it! :(
Any advice?
Cheers,
Peter
In cases like this I'm fond of putting in a debugging statement like:
(let [response .... ]
(log/errorf "in: request was: %s"
(with-out-str (clojure.pprint/pprint request))
....
and look for the data you want in the output (then remove the statement) or if you have a working and modern emacs+cider environment you can add debugging to the function with C-uC-cC-c and catch the value of request that way. If the data you wan't is available it will likely be in that output. If you are not using a logging framework then remove the log and with-out-str parts and just call pprint directly.
Sorry if i'm misunderstanding or perhaps is's a typo in the question though:
(let [response handler]
(println "out")
response)
looks like it's returning the handler itself rather than the result of calling that handler, should it be :
(let [response (handler request)]
(println "out")
response)

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"]

How to write a login function in luminus or use friend?

I am beginning to use luminus framework to develop a web app, and I am trying to use friend for auth, I am stacked here, I don't know how to use that like using gem in rails app.
I don't know where should I put the code in luminus, is there anyone can show me a demo. Or tell me what to do next?
Well, you can also tell me how to write a log in function in luminus.
The login sort of works like it is posted in the Luminus Docs. Not sure if you managed to read that part, but I'll show you a simplified version of the code I use. I want to mention that I removed quite a bit of code to make everything a bit easier to understand, so this may not work as-is since I only deleted code and extra parens. Since it is from actual working code, it will work with a bit of tweeking:
The first part is getting the login form:
(defn login-page []
(html5
[:h3 "Login"]
[:form {:method "POST" :action "login"}
[:div "Username:"
[:input {:type "text" :name "username" :required "required"}]]
[:div "Password:"
[:input {:type "password" :name "password" :required "required"}]]
[:div
[:input {:type "submit" :value "Log In"}]]]]))
Notice that there is a "POST" method? In order to get the routes to work, you have to have a "POST" route, but you will also need a "GET" route. This is the simplified version of the "GET" "POST" loop that I have:
(defroutes app-routes
(GET "/login" []
(log/login-page))
(POST "/login" [username password]
(do-login username password)))
The (do-login) function is where I authenticate the user / password combo, which then sets the session, which is shown downn below.
Notice that the POST route needs arguments. The arguments must match the "name" parameters in the form.
Finally, to get it all to work, you have to hook up some sessions. I personally use lib-noir.sessions:
(ns myapp.handler
(:require [noir.session :as sesh])
Then you have to create a map to hold the session, which I'm wrapping in a function here (note that the :key must match whatever you have in your database:
(defn set-user [username]
(sesh/put! :handle username))
And finally, you have to tell clojure that you want to allow sessions to be handled via middleware:
(def app
(sesh/wrap-noir-session
(handler/site
app-routes)))
Hopefully that gives you a bit of a headstart. I did not include how to connect to a database or how to use a map, but the above should be enough to get you on your way. I also did not touch on authorization and security (please don't skip this!). Using a database, map, or friend isn't a huge quantum leap from here. Just wanted to offer just enough to get you started.
Here's an example from when I did a luminus+friend combination, granted, they've changed the template several times, so this is from an older version, but the concepts the same, I hope it helps.
(def all-routes
[home-routes cljs-routes test-routes app-routes])
(def app
(-> all-routes middleware/app-handler ))
(def secured-app
(handler/site
(friend/authenticate app{
:login-uri "/login"
:unauthorized-redirect-uri "/login"
:credential-fn (partial creds/bcrypt-credential-fn users)
:workflows [(workflows/interactive-form)]})))
(def war-handler
(middleware/war-handler secured-app))

How to remove duplication in request validation?

I have a compojure app with a set of routes and handlers.
(defroutes app-routes
(GET "/stuff/:id" [:as request] (stuff/get-stuff request))
(POST "/stuff/" [:as request] (stuff/create-stuff request))
Each handler validates its input, like so
(defn create-stuff
[request]
(my-validation/validate-request
request
my-validation/create-stuff-validator
stuff-ok-fn))
The validation code is based on Metis, and looks like this:
(metis/defvalidator :create-stuff-validator
[:db :presence])
(defn validate-request
[request request-validator ok-function]
(let [validation-result (request-validator request)]
(if (empty? validation-result)
(ok-function request)
(bad-request validation-result))))
My problem is that code in create-stuff is duplicated across each of the route handlers; i.e the get-stuff function looks like the create-stuff handler. The only thing that differs is their validator function and their the-validation-went-well-function.
How can I abstract this duplication in a idiomatic Clojure manner?
Since this is a functional language, I suggest passing the functions that differentiate the handlers into a generic handler function.
;;; in core.clj
(defroutes app-routes
(GET "/stuff/:id" [:as request]
(handlers/handle
my-validation/get-stuff-validator
stuff/get-stuff-ok-fn
request))
(POST "/stuff/" [:as request]
(handlers/handle
my-validation/create-stuff-validator
stuff/create-stuff-ok-fn
request)))
;;; in handlers.clj
(defn handle
[validator action request]
(let [validation-result (validator request)]
(if (empty? validation-result)
(action request)
(bad-request validation-result))))
Stylistically, I suggest that the code would be easier to read if you avoid the smurf naming convention. The namespace tells us if you are validating, or that "stuff" is what you are operating on, you don't need to include it in the name of the function. Also, the fact that you are passing an argument that should be callable is sufficient, you don't need to put fn in the name of the function, the fact that it is passed as the ok branch tells us it is the thing to do when things go ok.
;;; in core.clj
(defroutes app-routes
(GET "/stuff/:id" [:as request]
(handlers/handle
my-validation/get-stuff
stuff/get
request))
(POST "/stuff/" [:as request]
(handlers/handle
my-validation/create-stuff
stuff/create
request)))
;;; in handlers.clj
(defn handle
[validator ok request]
(let [errors (validator request)]
(if (empty? errors)
(ok request)
(bad-request errors))))
if you can reduce verbosity without losing clarity, you improve correctness, because errors hide in verbosity.