Clojure what does #' mean - clojure

I am following this tutorial building a Clojure backend
and I'm not exactly well versed in Clojure.
The tutorial provides this source file
(ns shouter.web
(:require [compojure.core :refer [defroutes GET]]
[ring.adapter.jetty :as ring]))
(defroutes routes
(GET "/" [] "<h2>Hello World</h2>"))
(defn -main []
(ring/run-jetty #'routes {:port 8080 :join? false}))
what exactly does the #' mean? I know somehow it's getting the value of routes but why can you not just say
(ring/run-jetty routes {:port 8080 :join? false}))
Is the #' a ring specific syntax? Couldn't find any good resources on the matter.

#'sym expands to (var sym).
A var can be used interchangeably as the function bound to it. However, invoking a var resolves the defined function dynamically and then invokes it.
In this case it serves development purposes: Instead of passing the handler function routes by value, the var it is bound to is passed so that Jetty does not have to be restarted after you change and re-evaluate shouter.web/routes.

Related

How to make a ring server reload on file change?

How do you make a ring server reload during development whenever a file changes?
Add this dependency to your project.clj:
[ring/ring-devel "1.8.0"]
You can get the latest version number from Clojars.
Then require the following in the file where your request handler lives:
(:require [ring.middleware.reload :refer [wrap-reload]])
The wrap your handler:
(wrap-reload handler)
Example from a server using multiple wrappers:
(def handler
(compojure/routes
(GET "/" [] "hello world")
(route/not-found "No such page.")))
(defn -main []
(server/run-server
(-> handler
params/wrap-params
wrap-reload)
{:port 8080}))
You can find the documentation on the reload middleware here, and another example on how to use it here.

Parse JSON body from HTTP request (with ring and re-frame-http-fx)

I have a re-frame-based UI and try to communicate with my server using re-frame-http-fx. Sending and responding seems to work. However, I can't figure out how to parse the JSON body into a Clojure map on the server.
Here is my handler.clj as minimal as I could get it:
(ns my.handler
(:require [compojure.core :refer [GET POST defroutes]]
[compojure.route :refer [resources]]
[ring.util.response :refer [resource-response]]
[ring.middleware.json :refer [wrap-json-response wrap-json-body]]))
(defn json-post [request]
(let [body (:body request)]
(prn body)
body))
(defroutes routes
(GET "/" [] (resource-response "index.html" {:root "public"}))
(POST "/post" request json-post)
(resources "/"))
(def handler (wrap-json-response (wrap-json-body routes {:keywords? true})))
As far as I understand, the wrap-json-body middleware should replace the request body by a parsed version (a map?).
However, the output I get from (prn body) in my json-post handler is something like this:
#object[org.httpkit.BytesInputStream 0xda8b162 "BytesInputStream[len=41]"]
If I try something like (prn (:title body)) I get nil (although the original map-turned-json-request contains :title, as well as both the request and response body).
The request and response contain the correct json. The request Content-Type is correctly set to application/json (sent by re-frame-http-fx). The length of the buffer (41) is also the correct body length as per request.
I am running out of things to try. Any ideas?
While investigating the issue further, I found my error that lead to the effect. It concerns the dev-handler from the re-frame template that I conventiently omitted from my minimal example in the question.
I did not realize it was a problem, because the application seems to start fine even if you delete the entire definition of dev-handler from handler.clj, I assume because the server is initialized with handler in server.clj anyway (and the client does not fail fatally).
However, in project.clj of the re-frame template, the following is configured for figwheel:
:figwheel {:css-dirs ["resources/public/css"]
:ring-handler my.handler/dev-handler}
This leads to middleware configured for handler not being applied to my requests, thus not unwrapping the json body. Changing either the definition of dev-handler (the the same as handler in the question) or the configuration of figwheel in project.clj (to point to handler instead of dev-handler) solves the problem.
If anybody knows the reasoning of different handlers in project.clj and server.clj, feel free to let me know.

Clojure namespace not accessible

I'm trying to load two namespaces from the library "spurious-aws-sdk-helper" (which by the way I've installed locally - this is me testing it before deploying to Clojars). And I'm loading the namespaces from inside an if statement.
Once the namespaces are loaded I call a function which is provided by one of the loaded namespaces.
The problem is that when executing the code via lein ring server I get a Java exception informing me that the namespace I'm trying to access isn't available.
But if I run lein repl and then (use 'spurious-clojure-example.routes.home) the relevant top level namespace; then (require '[spurious-aws-sdk-helper.core :as core]) the namespace - much like in the code I'll linked to in a moment demonstrates - then the namespace WILL be available and subsequently the call to the function won't error?
I'm not sure if it's one of those errors which are misleading and in fact it's not the namespace I'm trying to require that's the problem, but something inside of it that's the issue? But if that was true then why would it work when called manually by myself within lein repl?
The code I'm referring to is: https://github.com/Integralist/spurious-clojure-example/blob/baseline/src/spurious_clojure_example/routes/home.clj#L9-L10
(ns spurious-clojure-example.routes.home
(:use [amazonica.aws.s3])
(:require [compojure.core :refer :all]
[environ.core :refer [env]]
[spurious-clojure-example.views.layout :as layout]))
(if (env :debug)
(do
(require '[spurious-aws-sdk-helper.core :as core])
(require '[spurious-aws-sdk-helper.utils :refer [endpoint cred]])
(core/configure {:s3 "test-bucket4"
:sqs "test-queue4"
:ddb (slurp "./resources/config/schema.yaml")})))
(def bucket-path "news-archive/dev/election2014-council_title")
(def content
(apply str (line-seq
(clojure.java.io/reader
(:object-content
(get-object (cred (endpoint :spurious-s3)) :bucket-name "shared" :key bucket-path))))))
(defn home []
(layout/common [:h1 content]))
(defroutes home-routes
(GET "/" [] (home)))
It's the (core/configure ...) call that triggers a Java exception saying "core" namespace isn't available. But running the following code from lein repl works fine...
(use 'spurious-clojure-example.routes.home)
(require '[spurious-aws-sdk-helper.core :as core])
(core/configure ...rest of code...)
UPDATE 1:
Just to clarify I've updated the code as follows...
(when (env :debug)
(require '[spurious-aws-sdk-helper.core :as core])
(require '[spurious-aws-sdk-helper.utils :refer [endpoint cred]])
(core/configure
{:s3 "test-bucket7"
:sqs "test-queue9"
:ddb (slurp "./resources/config/schema.yaml")}))
...and when running it within the REPL it works fine.
The problem is when running it via lein ring server.
I've started reading about (ns-resolve) here: http://technomancy.us/143
But the solution it suggests: (ns-resolve 'core 'configure) didn't work; it just threw an Unable to resolve symbol: core in this context error.
I created a app with lein new compojure-app and when :debug value is truthy, require clojure.string :as str and then also printing something to shell.
The code below works via lein ring server. I tested it with :debug values true and false. I see in your example, you use environ so, I put {:debug true} or {:debug false} in .lein-env.
(ns integralist.handler
(:require [compojure.core :refer [defroutes routes]]
[ring.middleware.resource :refer [wrap-resource]]
[ring.middleware.file-info :refer [wrap-file-info]]
[hiccup.middleware :refer [wrap-base-url]]
[compojure.handler :as handler]
[compojure.route :as route]
[integralist.routes.home :refer [home-routes]]
[environ.core :refer [env]]))
(when (env :debug)
(require '[clojure.string :as str]))
(when (env :debug)
(defn it-works! []
(println "It works!:" (str/split "Clojure is Awesome" #" "))))
(defn init []
(println "integralist is starting")
(when (env :debug)
(it-works!)))
(defn destroy []
(println "integralist is shutting down"))
(defroutes app-routes
(route/resources "/")
(route/not-found "Not Found"))
(def app
(-> (routes home-routes app-routes)
(handler/site)
(wrap-base-url)))
Tried it with:
(when true ; also tried with false
(require '[clojure.string :as str])
(str/split "Clojure is awesome!" #" "))
=> No such namespace: str
I'm a tiny bit surprised as well since if and when should only evaluate the body of their expressions for the appropriate branch and not touch the other expressions. I did not expect a namespace error on false.
More surprising is I did not expect a namespace error on true as well. I'd guess it's some java compilation thing trying to resolve the namespace even before code evaluation. I don't know the specifics of why.
As for what you should do, this code is funky and I've never thought of or seen anyone doing anything similar. Unless there is some specific reason for doing this, the solution is simple: shove your requires to the very top in ns. There's no need to change anything else.

Provide multiple implementations for a Clojure protocol

I have a namespace that exposes common data-related functions (get-images, insert-user). I then have two database backends that have those same functions and implement them differently. They implement the interface as it were. Each backend is contained within a namespace.
I can't seem to be able to find a good solution on how to accomplish this.
I tried dynamically loading the ns but no luck. Once you do (:require [abc :as x]), the x isn't a real value.
I tried using defprotocol and deftype but that's all kinds of weird because the functions in the deftype need to be imported, too and that messes everything up for me.
Is there some idiomatic solution to this?
I don't see why protocols are not sufficient?
In ns data.api:
(ns data.api)
(defprotocol DB
(get-images [this])
(insert-user [this]))
In ns data.impl1:
(ns data.impl1
(:require [data.api :refer :all]))
(defrecord Database1 [connection-params]
DB
(get-images [_] ...)
(insert-user [_] ...))
Same thing in ns data.impl2.
Then when you go to use a particular db, just create the correct record:
(ns data.user
(:require [data.api :refer :all])
[data.impl1 :refer (->Database1)])
(defn use-db []
(let [db1 (->Database1 {})]
(get-images db1)))

Compojure development without web server restarts

I've written a small Swing App before in Clojure and now I'd like to create an Ajax-style Web-App. Compojure looks like the best choice right now, so that's what I'm going to try out.
I'd like to have a real tiny edit/try feedback-loop, so I'd prefer not to restart the web server after each small change I do.
What's the best way to accomplish this? By default my Compojure setup (the standard stuff with ant deps/ant with Jetty) doesn't seem to reload any changes I do. I'll have to restart with run-server to see the changes. Because of the Java-heritage and the way the system is started etc. This is probably perfectly normal and the way it should be when I start the system from command-line.
Still, there must be a way to reload stuff dynamically while the server is running. Should I use Compojure from REPL to accomplish my goal? If I should, how do I reload my stuff there?
This is quite an old question, and there have been some recent changes that make this much easier.
There are two main things that you want:
Control should return to the REPL so you can keep interacting with your server. This is accomplished by adding {:join? false} to options when starting the Jetty server.
You'd like to automatically pick up changes in certain namespaces when the files change. This can be done with Ring's "wrap-reload" middleware.
A toy application would look like this:
(ns demo.core
(:use webui.nav
[clojure.java.io]
[compojure core response]
[ring.adapter.jetty :only [run-jetty]]
[ring.util.response]
[ring.middleware file file-info stacktrace reload])
(:require [compojure.route :as route] view)
(:gen-class))
; Some stuff using Fleet omitted.
(defroutes main-routes
(GET "/" [] (view/layout {:body (index-page)})
(route/not-found (file "public/404.html"))
)
(defn app
[]
(-> main-routes
(wrap-reload '(demo.core view))
(wrap-file "public")
(wrap-file-info)
(wrap-stacktrace)))
(defn start-server
[]
(run-jetty (app) {:port 8080 :join? false}))
(defn -main [& args]
(start-server))
The wrap-reload function decorates your app routes with a function that detects changes in the listed namespaces. When processing a request, if those namespaces have changed on disk, they are reloaded before further request processing. (My "view" namespace is dynamically created by Fleet, so this auto-reloads my templates whenever they change, too.)
I added a few other pieces of middleware that I've found consistently useful. wrap-file handles static assets. wrap-file-info sets the MIME type on those static assets. wrap-stacktrace helps in debugging.
From the REPL, you could start this app by using the namespace and calling start-server directly. The :gen-class keyword and -main function mean that the app can also be packaged as an uberjar for startup from outside the REPL, too. (There's a world outside the REPL? Well, some people have asked for it anyway...)
Here's an answer I got from James Reeves in the Compojure Google Group (the answer's here with his permission):
You can reload a namespace in Clojure using the :reload key on the use
or require commands. For example, let's say you have a file "demo.clj" that contains your routes:
(ns demo
(:use compojure))
(defroutes demo-routes
(GET "/"
"Hello World")
(ANY "*"
[404 "Page not found"]))
At the REPL, you can use this file and start a server:
user=> (use 'demo)
nil
user=> (use 'compojure)
nil
user=> (run-server {:port 8080} "/*" (servlet demo-routes))
...
You could also put the run-server command in another clojure file.
However, you don't want to put it in the same file as the stuff you want to reload.
Now make some changes to demo.clj. At the REPL type:
user=> (use 'demo :reload)
nil
And your changes should now show up on http://localhost:8080
I wanted to add an answer, since things have changed a bit since the newest answer and I had spent a bit of time looking for this myself.
Install leiningen (just follow the instructions there)
Create project
lein new compojure compojure-test
Edit the ring section of project.clj
:ring {:handler compojure-test.handler/app
:auto-reload? true
:auto-refresh? true}
Start the server on whatever port you want
lein ring server-headless 8080
Check that the server is running in your browser, the default base route should just say "Hello world". Next, go modify your handler (it's in src/project_name). Change the hello world text, save the file and reload the page in your browser. It should reflect the new text.
Following up on Timothy's link to Jim Downing's setup, I recently posted on a critical addition to that baseline that I found was necessary to enable automatic redeployment of compojure apps during development.
I have a shell script that looks like this:
#!/bin/sh
CLASSPATH=/home/me/install/compojure/compojure.jar
CLASSPATH=$CLASSPATH:/home/me/clojure/clojure.jar
CLASSPATH=$CLASSPATH:/home/me/clojure-contrib/clojure-contrib.jar
CLASSPATH=$CLASSPATH:/home/me/elisp/clojure/swank-clojure
for f in /home/me/install/compojure/deps/*.jar; do
CLASSPATH=$CLASSPATH:$f
done
java -server -cp $CLASSPATH clojure.lang.Repl /home/me/code/web/web.clj
web.clj looks like this
(use '[swank.swank])
(swank.swank/ignore-protocol-version "2009-03-09")
(start-server ".slime-socket" :port 4005 :encoding "utf-8")
Whenever I want to update the server I create an ssh tunnel from my local machine to the remote machine.
Enclojure and Emacs (running SLIME+swank-clojure) can connect to the remote REPL.
This is highly configuration dependent but works for me and I think you can adapt it:
Put compojure.jar and the jars under the compojure/deps directory are in your classpath. I use clojure-contrib/launchers/bash/clj-env-dir to do this, all you need to do is set the directory in CLOJURE_EXT and it will find the jars.
CLOJURE_EXT Colon-delimited list of paths to directories whose top-level
contents are (either directly or as symbolic links) jar
files and/or directories whose paths will be in Clojure's
classpath.
Launch clojure REPL
Paste in hello.clj example from compojure root directory
Check localhost:8080
Re-define the greeter
(defroutes greeter
(GET "/"
(html [:h1 "Goodbye World"])))
Check localhost:8080
There are also methods for attaching a REPL to an existing process, or you could keep a socket REPL embedded in your server or you could even define a POST call that will eval on the fly to allow you to redefine functions from the browser itself! There are lots of ways to approach this.
I'd like to follow up on mtnygard's answer and post the full project.clj file and core.clj file that got the given functionality working. A few modifications were made, and it's more barebones
pre-setup commands
lein new app test-web
cd test-web
mkdir resources
project.clj
(defproject test-web "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.5.1"]
[compojure "1.1.6"]
[ring "1.2.1"]]
:main ^:skip-aot test-web.core
:target-path "target/%s"
:profiles {:uberjar {:aot :all}})
core.clj
(ns test-web.core
(:use
[clojure.java.io]
[compojure core response]
[ring.adapter.jetty :only [run-jetty]]
[ring.util.response]
[ring.middleware file file-info stacktrace reload])
(:require [compojure.route :as route])
(:gen-class))
(defroutes main-routes
(GET "/" [] "Hello World!!")
(GET "/hello" [] (hello))
(route/not-found "NOT FOUND"))
(def app
(-> main-routes
(wrap-reload '(test-web.core))
(wrap-file "resources")
(wrap-file-info)
(wrap-stacktrace)))
(defn hello []
(str "Hello World!"))
(defn start-server
[]
(run-jetty #'app {:port 8081 :join? false}))
(defn -main [& args]
(start-server))
Pay Attention to the change from (defn app ...) to (def app ...)
This was crucial to getting the jetty server to work correctly
Compojure uses ring internally (by the same author), the ring web server options allow automatic realoading. So two alternatives would be :
lein ring server
lein ring server-headless
lein ring server 4000
lein ring server-headless 4000
Note that :
You need to have a line in your project.clj file that looks like:
:ring {:handler your.app/handler}