Ring
Web Apps in Idiomatic Clojure

       Mark McGranaghan


        January 23, 2010
About Mark



    Bowdoin College ’10
    Clojure user since 2008
    Open source: http://github.com/mmcgrana
Motivation for Ring
Motivation for Ring


     Abstract HTTP
Motivation for Ring


     Abstract HTTP
     Write apps in idiomatic Clojure
Motivation for Ring


     Abstract HTTP
     Write apps in idiomatic Clojure
     Share code across web frameworks
Motivation for Ring


     Abstract HTTP
     Write apps in idiomatic Clojure
     Share code across web frameworks
     Deploy on a variety of web servers
Motivation for Ring


     Abstract HTTP
     Write apps in idiomatic Clojure
     Share code across web frameworks
     Deploy on a variety of web servers
     WSGI & Rack
The Ring Project
The Ring Project



     Spec
The Ring Project



     Spec
     Library
The Ring Project



     Spec
     Library
     Ecosystem
Overview of Ring
Overview of Ring


     Handlers are functions
Overview of Ring


     Handlers are functions
     that take requests as Clojure maps
Overview of Ring


     Handlers are functions
     that take requests as Clojure maps
     and return responses as Clojure map
Overview of Ring


     Handlers are functions
     that take requests as Clojure maps
     and return responses as Clojure map
     Adapters run handlers on a web server
Overview of Ring


     Handlers are functions
     that take requests as Clojure maps
     and return responses as Clojure map
     Adapters run handlers on a web server
     Middleware augments handlers
“Ring”
Request Map


  {:uri              <String>
   :query-string     <String>
   :request-method   <Keyword>
   :headers          <IPersistentMap>
   :body             <InputStream>
   ...               ...}
Response Map



  {:status <Integer>
   :headers <IPersistentMap>
   :body    <String, ISeq, File, InputStream>}
Example: Hello World


  (defn app [req]
    {:status 200
     :headers {"Content-Type" "text/html"}
     :body    (str "Hi from " (:server-name req))})
Example: Hello World


  (defn app [req]
    {:status 200
     :headers {"Content-Type" "text/html"}
     :body    (str "Hi from " (:server-name req))})

  (use ’ring.adapter.jetty)

  (run-jetty app {:port 8080})
Example: Hello World
Example: Stacktraces


  (defn app [req]
    ("o noes"))
Example: Stacktraces


  (defn app [req]
    ("o noes"))

  (use ’ring.adapter.jetty)
  (use ’ring.middleware.stacktrace)

  (run-jetty (wrap-stacktrace app) {:port 8080})
Example: Stacktraces
Example: Static Files

  (defn dynamic-app [req]
    (...))
Example: Static Files

  (defn dynamic-app [req]
    (...))

  (use ’ring.middleware.file)
  (use ’ring.middleware.file-info)

  (def app
    (-> dynamic-app
      (wrap-file "public")
      (wrap-file-info)))
Example: Testability
Example: Testability


  (defn my-app [req]
    (...))
Example: Testability


  (defn my-app [req]
    (...))

  (deftest not-found-error
    (let [req {:uri "/bogus/uri"}
          resp (my-app req)]
      (is (= 404 (:status resp)))))
Ring and Web Frameworks
Ring and Web Frameworks



     Foundation, not replacement
Ring and Web Frameworks



     Foundation, not replacement
     Avoid duplication and share code
Ring and Web Frameworks



     Foundation, not replacement
     Avoid duplication and share code
     Compojure, Conjure, Weld all targeting Ring
Ring and Web Frameworks



     Foundation, not replacement
     Avoid duplication and share code
     Compojure, Conjure, Weld all targeting Ring
     Compojure case study
Ring Middleware
Ring Middleware


     ring.middleware.reload: Automatically
     reload namespaces
Ring Middleware


     ring.middleware.reload: Automatically
     reload namespaces
     ring.middleware.params: Get request
     params as a map
Ring Middleware


     ring.middleware.reload: Automatically
     reload namespaces
     ring.middleware.params: Get request
     params as a map
     ring.middleware.cookies: Cookie jar
     abstraction
Other Components
Other Components


    ring.util.servlet: If you really want a
    Servlet
Other Components


    ring.util.servlet: If you really want a
    Servlet
    ring.adapter.httpcore: Adapter for HTTP
    Core library
Other Components


    ring.util.servlet: If you really want a
    Servlet
    ring.adapter.httpcore: Adapter for HTTP
    Core library
    ring.handler.dump: See the request map
Other Components


    ring.util.servlet: If you really want a
    Servlet
    ring.adapter.httpcore: Adapter for HTTP
    Core library
    ring.handler.dump: See the request map
    ring.examples.*: Runnable examples
Future Work
Future Work


     Middleware and utility extraction from
     frameworks
Future Work


     Middleware and utility extraction from
     frameworks
     Not a framework itself
Future Work


     Middleware and utility extraction from
     frameworks
     Not a framework itself
     More use in production?
Future Work


     Middleware and utility extraction from
     frameworks
     Not a framework itself
     More use in production?
     User needs?
Learn More



     http://github.com/mmcgrana/ring
     ring/example/*.clj
     ring/SPEC

Ring: Web Apps in Idiomatic Clojure

  • 1.
    Ring Web Apps inIdiomatic Clojure Mark McGranaghan January 23, 2010
  • 2.
    About Mark Bowdoin College ’10 Clojure user since 2008 Open source: http://github.com/mmcgrana
  • 3.
  • 4.
    Motivation for Ring Abstract HTTP
  • 5.
    Motivation for Ring Abstract HTTP Write apps in idiomatic Clojure
  • 6.
    Motivation for Ring Abstract HTTP Write apps in idiomatic Clojure Share code across web frameworks
  • 7.
    Motivation for Ring Abstract HTTP Write apps in idiomatic Clojure Share code across web frameworks Deploy on a variety of web servers
  • 8.
    Motivation for Ring Abstract HTTP Write apps in idiomatic Clojure Share code across web frameworks Deploy on a variety of web servers WSGI & Rack
  • 9.
  • 10.
  • 11.
    The Ring Project Spec Library
  • 12.
    The Ring Project Spec Library Ecosystem
  • 13.
  • 14.
    Overview of Ring Handlers are functions
  • 15.
    Overview of Ring Handlers are functions that take requests as Clojure maps
  • 16.
    Overview of Ring Handlers are functions that take requests as Clojure maps and return responses as Clojure map
  • 17.
    Overview of Ring Handlers are functions that take requests as Clojure maps and return responses as Clojure map Adapters run handlers on a web server
  • 18.
    Overview of Ring Handlers are functions that take requests as Clojure maps and return responses as Clojure map Adapters run handlers on a web server Middleware augments handlers
  • 19.
  • 20.
    Request Map {:uri <String> :query-string <String> :request-method <Keyword> :headers <IPersistentMap> :body <InputStream> ... ...}
  • 21.
    Response Map {:status <Integer> :headers <IPersistentMap> :body <String, ISeq, File, InputStream>}
  • 22.
    Example: Hello World (defn app [req] {:status 200 :headers {"Content-Type" "text/html"} :body (str "Hi from " (:server-name req))})
  • 23.
    Example: Hello World (defn app [req] {:status 200 :headers {"Content-Type" "text/html"} :body (str "Hi from " (:server-name req))}) (use ’ring.adapter.jetty) (run-jetty app {:port 8080})
  • 24.
  • 25.
    Example: Stacktraces (defn app [req] ("o noes"))
  • 26.
    Example: Stacktraces (defn app [req] ("o noes")) (use ’ring.adapter.jetty) (use ’ring.middleware.stacktrace) (run-jetty (wrap-stacktrace app) {:port 8080})
  • 27.
  • 28.
    Example: Static Files (defn dynamic-app [req] (...))
  • 29.
    Example: Static Files (defn dynamic-app [req] (...)) (use ’ring.middleware.file) (use ’ring.middleware.file-info) (def app (-> dynamic-app (wrap-file "public") (wrap-file-info)))
  • 30.
  • 31.
    Example: Testability (defn my-app [req] (...))
  • 32.
    Example: Testability (defn my-app [req] (...)) (deftest not-found-error (let [req {:uri "/bogus/uri"} resp (my-app req)] (is (= 404 (:status resp)))))
  • 33.
    Ring and WebFrameworks
  • 34.
    Ring and WebFrameworks Foundation, not replacement
  • 35.
    Ring and WebFrameworks Foundation, not replacement Avoid duplication and share code
  • 36.
    Ring and WebFrameworks Foundation, not replacement Avoid duplication and share code Compojure, Conjure, Weld all targeting Ring
  • 37.
    Ring and WebFrameworks Foundation, not replacement Avoid duplication and share code Compojure, Conjure, Weld all targeting Ring Compojure case study
  • 38.
  • 39.
    Ring Middleware ring.middleware.reload: Automatically reload namespaces
  • 40.
    Ring Middleware ring.middleware.reload: Automatically reload namespaces ring.middleware.params: Get request params as a map
  • 41.
    Ring Middleware ring.middleware.reload: Automatically reload namespaces ring.middleware.params: Get request params as a map ring.middleware.cookies: Cookie jar abstraction
  • 42.
  • 43.
    Other Components ring.util.servlet: If you really want a Servlet
  • 44.
    Other Components ring.util.servlet: If you really want a Servlet ring.adapter.httpcore: Adapter for HTTP Core library
  • 45.
    Other Components ring.util.servlet: If you really want a Servlet ring.adapter.httpcore: Adapter for HTTP Core library ring.handler.dump: See the request map
  • 46.
    Other Components ring.util.servlet: If you really want a Servlet ring.adapter.httpcore: Adapter for HTTP Core library ring.handler.dump: See the request map ring.examples.*: Runnable examples
  • 47.
  • 48.
    Future Work Middleware and utility extraction from frameworks
  • 49.
    Future Work Middleware and utility extraction from frameworks Not a framework itself
  • 50.
    Future Work Middleware and utility extraction from frameworks Not a framework itself More use in production?
  • 51.
    Future Work Middleware and utility extraction from frameworks Not a framework itself More use in production? User needs?
  • 52.
    Learn More http://github.com/mmcgrana/ring ring/example/*.clj ring/SPEC