DEV Community

Sean Walker
Sean Walker

Posted on

Clojure web development: what's a ring?

Clojure web development can be a pretty crazy place, there's quite a few ways to tackle an http request and get data into a database, but to keep things simple, and to shamelessly self-promote my full stack framework coast, I'll use coast to show you what the heck is going on with these crazy clojure people.

First things first, let's start with a standard interchangeable library for representing http requests: ring.

Here's what a barebones http server looks like with coast on clojure:

(ns your-project.core
  (:require [coast.core :as coast]))

(defn home [request]
  (coast/ok "You're coasting on clojure!"))

(def app (-> (coast/get "/" home)
             (coast/wrap-coast-defaults)))

(coast/start-server app {:port 1337}))

One thing that separates a ring-based http server in clojure from other languages is that your web app app in this example can be run and tested separately from the server, like this

(ns your-project.core
  (:require [coast.core :as coast]))

(defn home [request]
  (coast/ok "You're coasting on clojure!"))

(def app (-> (coast/get "/" home)
             (coast/wrap-coast-defaults)))

(app {:request-method :get
      :uri "/"})
; => "You're coasting on clojure!"

app is just a function and you can test it out without running a server! This to me, was mind blowing, testing just became really easy, and if you take a quick look at a ring request map, things get even easier:

{
 :uri "/" ; the url that someone requested
 :request-method :get ; the requested http method, could be :get, :head, :options,  :put, :post, or :delete
 :query-string {} ; parsed query string
 :headers {} ; any headers
 :body {} ; raw body that can be parsed into whatever you want!
 :server-port 1337 ; the port of the request
 :scheme :http ; http or https
}

That wrap-coast-defaults line is a bunch of ring middleware wrapped up so that you don't have to worry about each ring middleware and how to fit them all together to get a working web app, it basically gives you sessions (stored in a cookie by default... still working on that), it parses url and body params and adds a :params key to the request map, like this

(defn show-item [request]
  (let [id (get-in request [:params :id])]
    (coast/ok (str "id: " id))))

(def app (-> (coast/get "/items/:id" show-item)
             (coast/wrap-coast-defaults)))

(app {:request-method :get
      :uri "/items/123"})
; => id: 123

Not only will it match the params, it also coerces things like numbers, uuids, booleans and vectors too.


This is just the tip of the iceberg when it comes to clojure web development, if you're curious as to whether clojure is the right fit for your next web app, check out all of the clojure resources at clojure.org, docs at clojuredocs.org, and for coast specific stuff you can contact me any time and visit coast on github or coast's official site.

Top comments (0)