Ring: HTTP requests.
EDIT: There are a million ways to handle HTTP routing in Clojure: Ring, bidi, pedestal, playnice, gudu, Route One (to name some I found on google) and there may be many more that I don't know. Some are closer to the Clojure idea of data above all, but I chose Compojure. Seems to be the most popular, and that falls in line with my new restaurant routine: order the most popular item, because sometimes there's wisdom in the crowd.
Ring is a simple request handler based off Python's WSGI and Ruby's Rack. It can handle only very basic HTTP requests. If you search up Ring on Google, you'll come up with basically the same example over and over again, and it is a static single page application to show how the basic request system works. It goes something like this:
;; project.clj (defproject ring-example "1.0" :description "this is the most basic example" :dependencies [[org.clojure/clojure "1.9.0"] [ring/ring-core "1.6.3"] [ring/ring-jetty-adapter "1.6.3"]] :main solb.example-project)
This beautiful piece of example can be grabbed from Github (if you really want it for whatever reason) and ran with;; src/solb/ring.clj (ns solb.ring (:require [ring.adapter.jetty :refer [run-jetty]])) (defn handler [request] {:status 200 :headers {"Content-Type" "text/html"} :body "this is the example."}) (defn -main [& args] (run-jetty handler {:port 5000}))
lein run
in the main directory. Then navigate over to localhost:5000 and you should see your beautiful "this is the example." string. If you really fancied yourself a hacker, you could build your own routing system with only this library, but personally I'd rather have a little bit more built for me; which is why most use a library like Compojure.λλλ
Compojure: routing.
Let's take a look at something a little more interesting: Compojure. This is how one would really build a webapp in Clojure as Compojure is a much more all-encompassing routing tool with most of the features you'd really want. Let's take a look with a little example: (which can also be found here on my Github).;; project.clj
(defproject compojure-example "1.0.0" :description "this is the most basic example" :dependencies [[org.clojure/clojure "1.9.0"] [compojure "1.6.1"] [ring/ring-core "1.7.1"] [ring/ring-jetty-adapter "1.7.1"]] :main solb.compojure :plugins [[cider/cider-nrepl "0.21.1"]])
This shows the basics of routing.;; src/solb/compojure.clj
(ns solb.compojure (:require [compojure.core :refer :all] [compojure.route :as route] [ring.middleware.params :refer [wrap-params]] [ring.adapter.jetty :as jetty])) (defroutes app-routes (GET "/" [] "main page here!!") (GET "/user/:id" [id] (str "hihihi " id)) (POST "/post" [:as req] (str (:params req))) (route/not-found "404 page")) (def app (-> app-routes (wrap-params))) (defonce server (jetty/run-jetty #'app {:port 5000 :join? false})) (defn stop-server [] (.stop server)) (defn -main [& args] (.start server))
GET
, and POST
routes, and how to play a little bit with params. A few curl
's can show what we can do with Compojure. We also see that destructuring route$> curl localhost:5000
main page here!!
(GET "/user/:id" [id] (str "hihihi " id))
. This is of course quite an important feature of a website. My example is merely the simplest syntax, but there are many forms of destructuring syntax on the here on the Compojure github.Cool! Now to play with the POST route; located at the "/post" endpoint.$> curl localhost:5000/user/solb
hihihi sol
To use params, you have to wrap the handler with$> curl -X POST -d "name=solly&hobby=coding" localhost:5000/post
{"name" "solly", "hobby" "coding"}
wrap-params
, there are other ways to wrap parameters (such as wrap-multiparts-params
) but this is a simple one that works with the url-encoded parameters. Now that we have the basics of HTTP request systems, we can start really building something. We have a foundation to build on. In the next post I will play with Compojure a little more, but will also use Hiccup; the defacto way to compile Clojure down to HTML.