SlideShare a Scribd company logo
1 of 21
Download to read offline
Frameworkless Web Development in Clojure
Andreas ’Kungi’ Klein
24.01.2015
Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 1 / 21
Outline
1 Web programming in Clojure
2 HTTP Abstraction
3 Routing
4 HTML Templating
5 Authentication
6 Conclusion
7 Bibliography
Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 2 / 21
Web programming in Clojure
What’s I like?
No dominant web frameworks
No framework dependent paradigms
Just plain clojure data structures and functions
The full power of clojure is available in every ”step”
Web programming from the bottom up
Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 3 / 21
What’s nice to have for web programming?
The typical web framework offers:
Web Server / HTTP abstraction
Middlewares
Session
CSRF Protection
Request Routing
HTML Templating
Authentication
(Database abstraction)
(Communication with the frontend)
Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 4 / 21
Clojure’s libraries
Feature Library
HTTP Abstraction Ring
Middlewares Ring
Routing Clout / Compojure
HTML Templating Hiccup / Enlive
Authentication Friend
Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 5 / 21
What is Ring?
Ring is the most widely used Clojure interface between web servers and web
applications.
Similar technologies in other languages include
Plack (Perl)
Rack (Ruby)
Clack (Common Lisp)
WSGI (Python)
Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 6 / 21
Ring concepts
Client
Adapter
HTTP
Request
Ring
Request
Middleware
Ring
Request
Handler
Adapter
HTTP
Response
Ring
Response
Middleware
Ring
Response
Requests, Responses, Middlewares, Handlers, Adapters
Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 7 / 21
Ring example
Example project.clj
:dependencies [[org.clojure/clojure "1.6.0"]
[ring/ring-core "1.3.2"]]
:plugins [[lein-ring "0.9.1"]]
:ring {:handler ring-example.core/handler}
Example Ring handler
(ns ring-example.core)
(defn handler [request]
{:status 200
:headers {"Content-Type" "text/html"}
:body "Hello World"})
Start with
lein ring server
Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 8 / 21
Request / Response
Requests and responses are maps (see ring spec)
(require '[ring.mock.request :as mock])
(mock/request :get "/hallo")
=> {:server-port 80
:server-name "localhost"
:remote-addr "localhost"
:uri "/hallo"
:query-string nil
:scheme :http
:request-method :get
:headers {"host" "localhost"}}
(handler (mock/request :get "/hallo"))
=> {:headers {"Content-Type" "text/html"}
:status 200
:body "Hello World"}
Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 9 / 21
Middleware
A middleware is a higher order function that enhances a handler. The first
argument is a handler-function and the middleware itself returns a handler
function.
(defn wrap-content-type [handler content-type]
(fn [request]
(let [response (handler request)]
(assoc-in response [:headers "Content-Type"] content-type))))
Usage
(def app
(-> handler
(wrap-content-type "text/html")))
Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 10 / 21
Adapter
Adapters translate from a concrete web server to ring requests and responses. For
example ring.adapter.jetty as the name suggests connects ring to jetty. This
is where most of the magic happens:
(defn- proxy-handler
"Returns an Jetty Handler implementation
for the given Ring handler."
[handler]
(proxy [AbstractHandler] []
(handle [_ ^Request base-request request response]
(let [request-map (servlet/build-request-map request)
response-map (handler request-map)]
(when response-map
(servlet/update-servlet-response response
response-map)
(.setHandled base-request true))))))
Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 11 / 21
Clout
Clout is an HTTP matching library using the same syntax as Rails or Sinatra.
(require '[clout.core :as clout])
(require '[ring.mock.request :as mock])
(clout/route-matches "/article/:title/author/:name"
(mock/request :get "/article/clojure/author/rich"))
=> {:title "clojure" :name "rich"}
(clout/route-matches "/article/:title"
(mock/request :get "schnuff-schnuff"))
=> nil
Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 12 / 21
Compojure
Most of the time Clout is used through compojure. Compojure combines ring and
clout through a concise syntax.
(require '[compojure.core :refer [GET POST defroutes]])
(require '[ring.util.response :refer [redirect-after-post]])
(defroutes app
(GET "/article/:title" [title]
(str "Found article " title))
(POST "/article" request
(let [article (create-article (:body request))]
(reqirect-after-post (str "/article/" (:id article))))))
Compojure routes are ring handlers.
Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 13 / 21
Hiccup
Hiccup is a literal translation from HTML to clojure vectors and maps.
(use 'hiccup.page)
(html5
[:head [:title "How much do I love clojure?"]]
[:body [:h1 "Very Much!"]])
=> "<!DOCTYPE html>
<html>
<head><title>How much do I love clojure?</title></head>
<body><h1>Very Much!</h1></body>
</html>"
It also provides some CSS selector like shortcuts.
[:div#id.class-1.class2 "Schnuff!"]
=> "<div class="class-1 class2" id="id">Schnuff!</div>"
Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 14 / 21
Enlive
A completely different strategy to HTML templating is provided by Enlive. It
works with selectors and transformations.
Suppose the following HTML exists in test.html:
<!DOCTYPE html>
<html lang="en">
<head><title>This is a title placeholder</title></head>
<body><ul></ul></body>
</html>
(use '[net.cgrand.enlive-html])
(deftemplate main-template "test.html"
[foo]
[:head :title] (content (str "Enlive starter kit: " foo))
[:body :ul] (do-> (add-class "item-list")
(append (html [:li "Item 1"]))
(append (html [:li "Item 2"]))))
deftemplate creates a function which returns html.
Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 15 / 21
Friend
Friend calls itself an ”extensible authentication and authorization library for
Clojure Ring web applications and services.”
Works very well with ring/compojure
Provides role based authentication
Friend contains two mayor concepts
Credential functions
Authentication workflows (e.g. OAuth, HTTP Basic Auth, Login Form, …)
Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 16 / 21
Credential function example
A credential function returns either nil or a map representing the credentials like
{:username "joe"
:app.foo/passphrase "bcrypt hash"}
(defn bcrypt-credential-fn
[load-credentials-fn {:keys [username password]}]
(when-let [creds (load-credentials-fn username)]
(let [password-key (or (-> creds meta ::password-key)
:password)]
(when (bcrypt-verify password (get creds password-key))
(dissoc creds password-key)))))
Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 17 / 21
Workflow example
A workflow function either returns an authorization map containing the users
credentials or it delivers an error page depending on the kind of workflow. The
interactive-form workflow for example delivers a login page in case of failure.
See the following simplified example from the friend source:
(defn http-basic
[& {:keys [credential-fn realm] :as basic-config}]
(fn [{{:strs [authorization]} :headers :as request}]
(when (and authorization (re-matches #"s*Basics+(.+)" authorization))
(if-let [[[_ username password]] (extract-username-password ...)]
(if-let [user-record
((gets :credential-fn
basic-config
(::friend/auth-config request))
^{::friend/workflow :http-basic}
{:username username, :password password})]
(make-auth user-record
{::friend/workflow :http-basic
::friend/redirect-on-auth? false
::friend/ensure-session false})
(http-basic-deny realm request))
{:status 400
:body "Malformed Authorization header for HTTP Basic authentication."}))))
Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 18 / 21
Putting it together
(ns your.ring.app
(:require [cemerick.friend :as friend]
(cemerick.friend [workflows :as workflows]
[credentials :as creds])))
;; a dummy in-memory user "database"
(def users {"root" {:username "root"
:password (creds/hash-bcrypt "admin_password")
:roles #{::admin}}
"jane" {:username "jane"
:password (creds/hash-bcrypt "user_password")
:roles #{::user}}})
(def ring-app
;; ... assemble routes however you like ...
)
(def secured-app
(-> ring-app
(friend/authenticate
{:credential-fn (partial creds/bcrypt-credential-fn users)
:workflows [(workflows/interactive-form)]})
;; ...required Ring middlewares ...
))
Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 19 / 21
Frameworkless Web Development
What’s great about Frameworkless?
Small libraries can be composed easily
Communication between these libraries is easy because plain old clojure data
structures are used
Systems become easier through separation of concerns
Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 20 / 21
Bibliography
https://github.com/ring-clojure/ring
https://github.com/weavejester/clout
https://github.com/weavejester/compojure
https://github.com/weavejester/hiccup
https://github.com/cgrand/enlive
https://github.com/cemerick/friend
Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 21 / 21

More Related Content

What's hot

Better Selenium Tests with Geb - Selenium Conf 2014
Better Selenium Tests with Geb - Selenium Conf 2014Better Selenium Tests with Geb - Selenium Conf 2014
Better Selenium Tests with Geb - Selenium Conf 2014Naresha K
 
Chrome enchanted 2015
Chrome enchanted 2015Chrome enchanted 2015
Chrome enchanted 2015Chang W. Doh
 
Go Fullstack: JSF for Public Sites (CONFESS 2013)
Go Fullstack: JSF for Public Sites (CONFESS 2013)Go Fullstack: JSF for Public Sites (CONFESS 2013)
Go Fullstack: JSF for Public Sites (CONFESS 2013)Michael Kurz
 
Go Fullstack: JSF for Public Sites (CONFESS 2012)
Go Fullstack: JSF for Public Sites (CONFESS 2012)Go Fullstack: JSF for Public Sites (CONFESS 2012)
Go Fullstack: JSF for Public Sites (CONFESS 2012)Michael Kurz
 
HTML5 (and friends) - History, overview and current status - jsDay Verona 11....
HTML5 (and friends) - History, overview and current status - jsDay Verona 11....HTML5 (and friends) - History, overview and current status - jsDay Verona 11....
HTML5 (and friends) - History, overview and current status - jsDay Verona 11....Patrick Lauke
 
SharePoint and jQuery Essentials
SharePoint and jQuery EssentialsSharePoint and jQuery Essentials
SharePoint and jQuery EssentialsMark Rackley
 
Why and How to Use Virtual DOM
Why and How to Use Virtual DOMWhy and How to Use Virtual DOM
Why and How to Use Virtual DOMDaiwei Lu
 
Oleh Zasadnyy "Progressive Web Apps: line between web and native apps become ...
Oleh Zasadnyy "Progressive Web Apps: line between web and native apps become ...Oleh Zasadnyy "Progressive Web Apps: line between web and native apps become ...
Oleh Zasadnyy "Progressive Web Apps: line between web and native apps become ...IT Event
 
HTML5: where flash isn't needed anymore
HTML5: where flash isn't needed anymoreHTML5: where flash isn't needed anymore
HTML5: where flash isn't needed anymoreRemy Sharp
 
Simplify AJAX using jQuery
Simplify AJAX using jQuerySimplify AJAX using jQuery
Simplify AJAX using jQuerySiva Arunachalam
 
Top 45 jQuery Interview Questions and Answers | Edureka
Top 45 jQuery Interview Questions and Answers | EdurekaTop 45 jQuery Interview Questions and Answers | Edureka
Top 45 jQuery Interview Questions and Answers | EdurekaEdureka!
 
Angular를 활용한 웹 프론트단 개발과 2.0에서 달라진점
Angular를 활용한 웹 프론트단 개발과 2.0에서 달라진점Angular를 활용한 웹 프론트단 개발과 2.0에서 달라진점
Angular를 활용한 웹 프론트단 개발과 2.0에서 달라진점Jeado Ko
 
Pragmatic Browser Automation with Geb - GIDS 2015
Pragmatic Browser Automation with Geb - GIDS 2015Pragmatic Browser Automation with Geb - GIDS 2015
Pragmatic Browser Automation with Geb - GIDS 2015Naresha K
 
Medium TechTalk — iOS
Medium TechTalk — iOSMedium TechTalk — iOS
Medium TechTalk — iOSjimmyatmedium
 
Bootstrap과 UI-Bootstrap
Bootstrap과 UI-BootstrapBootstrap과 UI-Bootstrap
Bootstrap과 UI-BootstrapWebFrameworks
 
J query b_dotnet_ug_meet_12_may_2012
J query b_dotnet_ug_meet_12_may_2012J query b_dotnet_ug_meet_12_may_2012
J query b_dotnet_ug_meet_12_may_2012ghnash
 
jQuery Proven Performance Tips & Tricks
jQuery Proven Performance Tips & TricksjQuery Proven Performance Tips & Tricks
jQuery Proven Performance Tips & TricksAddy Osmani
 
Python Code Camp for Professionals 3/4
Python Code Camp for Professionals 3/4Python Code Camp for Professionals 3/4
Python Code Camp for Professionals 3/4DEVCON
 
Top 10 HTML5 features
Top 10 HTML5 featuresTop 10 HTML5 features
Top 10 HTML5 featuresGill Cleeren
 

What's hot (20)

Better Selenium Tests with Geb - Selenium Conf 2014
Better Selenium Tests with Geb - Selenium Conf 2014Better Selenium Tests with Geb - Selenium Conf 2014
Better Selenium Tests with Geb - Selenium Conf 2014
 
J query module1
J query module1J query module1
J query module1
 
Chrome enchanted 2015
Chrome enchanted 2015Chrome enchanted 2015
Chrome enchanted 2015
 
Go Fullstack: JSF for Public Sites (CONFESS 2013)
Go Fullstack: JSF for Public Sites (CONFESS 2013)Go Fullstack: JSF for Public Sites (CONFESS 2013)
Go Fullstack: JSF for Public Sites (CONFESS 2013)
 
Go Fullstack: JSF for Public Sites (CONFESS 2012)
Go Fullstack: JSF for Public Sites (CONFESS 2012)Go Fullstack: JSF for Public Sites (CONFESS 2012)
Go Fullstack: JSF for Public Sites (CONFESS 2012)
 
HTML5 (and friends) - History, overview and current status - jsDay Verona 11....
HTML5 (and friends) - History, overview and current status - jsDay Verona 11....HTML5 (and friends) - History, overview and current status - jsDay Verona 11....
HTML5 (and friends) - History, overview and current status - jsDay Verona 11....
 
SharePoint and jQuery Essentials
SharePoint and jQuery EssentialsSharePoint and jQuery Essentials
SharePoint and jQuery Essentials
 
Why and How to Use Virtual DOM
Why and How to Use Virtual DOMWhy and How to Use Virtual DOM
Why and How to Use Virtual DOM
 
Oleh Zasadnyy "Progressive Web Apps: line between web and native apps become ...
Oleh Zasadnyy "Progressive Web Apps: line between web and native apps become ...Oleh Zasadnyy "Progressive Web Apps: line between web and native apps become ...
Oleh Zasadnyy "Progressive Web Apps: line between web and native apps become ...
 
HTML5: where flash isn't needed anymore
HTML5: where flash isn't needed anymoreHTML5: where flash isn't needed anymore
HTML5: where flash isn't needed anymore
 
Simplify AJAX using jQuery
Simplify AJAX using jQuerySimplify AJAX using jQuery
Simplify AJAX using jQuery
 
Top 45 jQuery Interview Questions and Answers | Edureka
Top 45 jQuery Interview Questions and Answers | EdurekaTop 45 jQuery Interview Questions and Answers | Edureka
Top 45 jQuery Interview Questions and Answers | Edureka
 
Angular를 활용한 웹 프론트단 개발과 2.0에서 달라진점
Angular를 활용한 웹 프론트단 개발과 2.0에서 달라진점Angular를 활용한 웹 프론트단 개발과 2.0에서 달라진점
Angular를 활용한 웹 프론트단 개발과 2.0에서 달라진점
 
Pragmatic Browser Automation with Geb - GIDS 2015
Pragmatic Browser Automation with Geb - GIDS 2015Pragmatic Browser Automation with Geb - GIDS 2015
Pragmatic Browser Automation with Geb - GIDS 2015
 
Medium TechTalk — iOS
Medium TechTalk — iOSMedium TechTalk — iOS
Medium TechTalk — iOS
 
Bootstrap과 UI-Bootstrap
Bootstrap과 UI-BootstrapBootstrap과 UI-Bootstrap
Bootstrap과 UI-Bootstrap
 
J query b_dotnet_ug_meet_12_may_2012
J query b_dotnet_ug_meet_12_may_2012J query b_dotnet_ug_meet_12_may_2012
J query b_dotnet_ug_meet_12_may_2012
 
jQuery Proven Performance Tips & Tricks
jQuery Proven Performance Tips & TricksjQuery Proven Performance Tips & Tricks
jQuery Proven Performance Tips & Tricks
 
Python Code Camp for Professionals 3/4
Python Code Camp for Professionals 3/4Python Code Camp for Professionals 3/4
Python Code Camp for Professionals 3/4
 
Top 10 HTML5 features
Top 10 HTML5 featuresTop 10 HTML5 features
Top 10 HTML5 features
 

Viewers also liked

Swaggered web apis in Clojure
Swaggered web apis in ClojureSwaggered web apis in Clojure
Swaggered web apis in ClojureMetosin Oy
 
ClojuTRE2015: Kekkonen - making your Clojure web APIs more awesome
ClojuTRE2015: Kekkonen - making your Clojure web APIs more awesomeClojuTRE2015: Kekkonen - making your Clojure web APIs more awesome
ClojuTRE2015: Kekkonen - making your Clojure web APIs more awesomeMetosin Oy
 
Wieldy remote apis with Kekkonen - ClojureD 2016
Wieldy remote apis with Kekkonen - ClojureD 2016Wieldy remote apis with Kekkonen - ClojureD 2016
Wieldy remote apis with Kekkonen - ClojureD 2016Metosin Oy
 
Functional web with clojure
Functional web with clojureFunctional web with clojure
Functional web with clojureJohn Stevenson
 
Deconstructing the Functional Web with Clojure
Deconstructing the Functional Web with ClojureDeconstructing the Functional Web with Clojure
Deconstructing the Functional Web with ClojureNorman Richards
 
Euroclojure2014: Schema & Swagger - making your Clojure web APIs more awesome
Euroclojure2014: Schema & Swagger - making your Clojure web APIs more awesomeEuroclojure2014: Schema & Swagger - making your Clojure web APIs more awesome
Euroclojure2014: Schema & Swagger - making your Clojure web APIs more awesomeMetosin Oy
 
Ring: Web Apps in Idiomatic Clojure
Ring: Web Apps in Idiomatic ClojureRing: Web Apps in Idiomatic Clojure
Ring: Web Apps in Idiomatic ClojureMark McGranaghan
 
Clojure and the Web
Clojure and the WebClojure and the Web
Clojure and the Webnickmbailey
 
マイクロフレームワークEnkan(とKotowari)ではじめるREPL駆動開発
マイクロフレームワークEnkan(とKotowari)ではじめるREPL駆動開発マイクロフレームワークEnkan(とKotowari)ではじめるREPL駆動開発
マイクロフレームワークEnkan(とKotowari)ではじめるREPL駆動開発Yoshitaka Kawashima
 
Web programming in clojure
Web programming in clojureWeb programming in clojure
Web programming in clojurebdemchak
 

Viewers also liked (10)

Swaggered web apis in Clojure
Swaggered web apis in ClojureSwaggered web apis in Clojure
Swaggered web apis in Clojure
 
ClojuTRE2015: Kekkonen - making your Clojure web APIs more awesome
ClojuTRE2015: Kekkonen - making your Clojure web APIs more awesomeClojuTRE2015: Kekkonen - making your Clojure web APIs more awesome
ClojuTRE2015: Kekkonen - making your Clojure web APIs more awesome
 
Wieldy remote apis with Kekkonen - ClojureD 2016
Wieldy remote apis with Kekkonen - ClojureD 2016Wieldy remote apis with Kekkonen - ClojureD 2016
Wieldy remote apis with Kekkonen - ClojureD 2016
 
Functional web with clojure
Functional web with clojureFunctional web with clojure
Functional web with clojure
 
Deconstructing the Functional Web with Clojure
Deconstructing the Functional Web with ClojureDeconstructing the Functional Web with Clojure
Deconstructing the Functional Web with Clojure
 
Euroclojure2014: Schema & Swagger - making your Clojure web APIs more awesome
Euroclojure2014: Schema & Swagger - making your Clojure web APIs more awesomeEuroclojure2014: Schema & Swagger - making your Clojure web APIs more awesome
Euroclojure2014: Schema & Swagger - making your Clojure web APIs more awesome
 
Ring: Web Apps in Idiomatic Clojure
Ring: Web Apps in Idiomatic ClojureRing: Web Apps in Idiomatic Clojure
Ring: Web Apps in Idiomatic Clojure
 
Clojure and the Web
Clojure and the WebClojure and the Web
Clojure and the Web
 
マイクロフレームワークEnkan(とKotowari)ではじめるREPL駆動開発
マイクロフレームワークEnkan(とKotowari)ではじめるREPL駆動開発マイクロフレームワークEnkan(とKotowari)ではじめるREPL駆動開発
マイクロフレームワークEnkan(とKotowari)ではじめるREPL駆動開発
 
Web programming in clojure
Web programming in clojureWeb programming in clojure
Web programming in clojure
 

Similar to Frameworkless Web Development in Clojure

Going Serverless with Azure Functions
Going Serverless with Azure FunctionsGoing Serverless with Azure Functions
Going Serverless with Azure FunctionsShahed Chowdhuri
 
e-suap - client technologies- english version
e-suap - client technologies- english versione-suap - client technologies- english version
e-suap - client technologies- english versionSabino Labarile
 
Web Components With Rails
Web Components With RailsWeb Components With Rails
Web Components With RailsBoris Nadion
 
[convergese] Adaptive Images in Responsive Web Design
[convergese] Adaptive Images in Responsive Web Design[convergese] Adaptive Images in Responsive Web Design
[convergese] Adaptive Images in Responsive Web DesignChristopher Schmitt
 
Ajax Performance Tuning and Best Practices
Ajax Performance Tuning and Best PracticesAjax Performance Tuning and Best Practices
Ajax Performance Tuning and Best PracticesDoris Chen
 
Performance Optimization and JavaScript Best Practices
Performance Optimization and JavaScript Best PracticesPerformance Optimization and JavaScript Best Practices
Performance Optimization and JavaScript Best PracticesDoris Chen
 
Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2Hugo Hamon
 
JavaScript front end performance optimizations
JavaScript front end performance optimizationsJavaScript front end performance optimizations
JavaScript front end performance optimizationsChris Love
 
Securing Microservices using Play and Akka HTTP
Securing Microservices using Play and Akka HTTPSecuring Microservices using Play and Akka HTTP
Securing Microservices using Play and Akka HTTPRafal Gancarz
 
Developing your first application using FIWARE
Developing your first application using FIWAREDeveloping your first application using FIWARE
Developing your first application using FIWAREFIWARE
 
Web-Technologies 26.06.2003
Web-Technologies 26.06.2003Web-Technologies 26.06.2003
Web-Technologies 26.06.2003Wolfgang Wiese
 
VMWorld 2017 Hackathon training: Getting Started with Clarity
VMWorld 2017 Hackathon training: Getting Started with ClarityVMWorld 2017 Hackathon training: Getting Started with Clarity
VMWorld 2017 Hackathon training: Getting Started with ClarityJeeyun Lim
 
JavaScript DOM - Dynamic interactive Code
JavaScript DOM - Dynamic interactive CodeJavaScript DOM - Dynamic interactive Code
JavaScript DOM - Dynamic interactive CodeLaurence Svekis ✔
 
How to create an Angular builder
How to create an Angular builderHow to create an Angular builder
How to create an Angular builderMaurizio Vitale
 
An Introduction to Tornado
An Introduction to TornadoAn Introduction to Tornado
An Introduction to TornadoGavin Roy
 
It is not HTML5. but ... / HTML5ではないサイトからHTML5を考える
It is not HTML5. but ... / HTML5ではないサイトからHTML5を考えるIt is not HTML5. but ... / HTML5ではないサイトからHTML5を考える
It is not HTML5. but ... / HTML5ではないサイトからHTML5を考えるSadaaki HIRAI
 
The top 10 security issues in web applications
The top 10 security issues in web applicationsThe top 10 security issues in web applications
The top 10 security issues in web applicationsDevnology
 

Similar to Frameworkless Web Development in Clojure (20)

Going Serverless with Azure Functions
Going Serverless with Azure FunctionsGoing Serverless with Azure Functions
Going Serverless with Azure Functions
 
e-suap - client technologies- english version
e-suap - client technologies- english versione-suap - client technologies- english version
e-suap - client technologies- english version
 
Web Components With Rails
Web Components With RailsWeb Components With Rails
Web Components With Rails
 
Knolx session
Knolx sessionKnolx session
Knolx session
 
[convergese] Adaptive Images in Responsive Web Design
[convergese] Adaptive Images in Responsive Web Design[convergese] Adaptive Images in Responsive Web Design
[convergese] Adaptive Images in Responsive Web Design
 
Ajax Performance Tuning and Best Practices
Ajax Performance Tuning and Best PracticesAjax Performance Tuning and Best Practices
Ajax Performance Tuning and Best Practices
 
Performance Optimization and JavaScript Best Practices
Performance Optimization and JavaScript Best PracticesPerformance Optimization and JavaScript Best Practices
Performance Optimization and JavaScript Best Practices
 
Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2
 
Codegnitorppt
CodegnitorpptCodegnitorppt
Codegnitorppt
 
JavaScript front end performance optimizations
JavaScript front end performance optimizationsJavaScript front end performance optimizations
JavaScript front end performance optimizations
 
Securing Microservices using Play and Akka HTTP
Securing Microservices using Play and Akka HTTPSecuring Microservices using Play and Akka HTTP
Securing Microservices using Play and Akka HTTP
 
Developing your first application using FIWARE
Developing your first application using FIWAREDeveloping your first application using FIWARE
Developing your first application using FIWARE
 
Web-Technologies 26.06.2003
Web-Technologies 26.06.2003Web-Technologies 26.06.2003
Web-Technologies 26.06.2003
 
VMWorld 2017 Hackathon training: Getting Started with Clarity
VMWorld 2017 Hackathon training: Getting Started with ClarityVMWorld 2017 Hackathon training: Getting Started with Clarity
VMWorld 2017 Hackathon training: Getting Started with Clarity
 
JavaScript DOM - Dynamic interactive Code
JavaScript DOM - Dynamic interactive CodeJavaScript DOM - Dynamic interactive Code
JavaScript DOM - Dynamic interactive Code
 
Html5
Html5Html5
Html5
 
How to create an Angular builder
How to create an Angular builderHow to create an Angular builder
How to create an Angular builder
 
An Introduction to Tornado
An Introduction to TornadoAn Introduction to Tornado
An Introduction to Tornado
 
It is not HTML5. but ... / HTML5ではないサイトからHTML5を考える
It is not HTML5. but ... / HTML5ではないサイトからHTML5を考えるIt is not HTML5. but ... / HTML5ではないサイトからHTML5を考える
It is not HTML5. but ... / HTML5ではないサイトからHTML5を考える
 
The top 10 security issues in web applications
The top 10 security issues in web applicationsThe top 10 security issues in web applications
The top 10 security issues in web applications
 

Recently uploaded

The Most Attractive Pune Call Girls Budhwar Peth 8250192130 Will You Miss Thi...
The Most Attractive Pune Call Girls Budhwar Peth 8250192130 Will You Miss Thi...The Most Attractive Pune Call Girls Budhwar Peth 8250192130 Will You Miss Thi...
The Most Attractive Pune Call Girls Budhwar Peth 8250192130 Will You Miss Thi...ranjana rawat
 
Online banking management system project.pdf
Online banking management system project.pdfOnline banking management system project.pdf
Online banking management system project.pdfKamal Acharya
 
(ANJALI) Dange Chowk Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
(ANJALI) Dange Chowk Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...(ANJALI) Dange Chowk Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
(ANJALI) Dange Chowk Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...ranjana rawat
 
Call for Papers - African Journal of Biological Sciences, E-ISSN: 2663-2187, ...
Call for Papers - African Journal of Biological Sciences, E-ISSN: 2663-2187, ...Call for Papers - African Journal of Biological Sciences, E-ISSN: 2663-2187, ...
Call for Papers - African Journal of Biological Sciences, E-ISSN: 2663-2187, ...Christo Ananth
 
UNIT-III FMM. DIMENSIONAL ANALYSIS
UNIT-III FMM.        DIMENSIONAL ANALYSISUNIT-III FMM.        DIMENSIONAL ANALYSIS
UNIT-III FMM. DIMENSIONAL ANALYSISrknatarajan
 
VIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 Booking
VIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 BookingVIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 Booking
VIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 Bookingdharasingh5698
 
The Most Attractive Pune Call Girls Manchar 8250192130 Will You Miss This Cha...
The Most Attractive Pune Call Girls Manchar 8250192130 Will You Miss This Cha...The Most Attractive Pune Call Girls Manchar 8250192130 Will You Miss This Cha...
The Most Attractive Pune Call Girls Manchar 8250192130 Will You Miss This Cha...ranjana rawat
 
College Call Girls Nashik Nehal 7001305949 Independent Escort Service Nashik
College Call Girls Nashik Nehal 7001305949 Independent Escort Service NashikCollege Call Girls Nashik Nehal 7001305949 Independent Escort Service Nashik
College Call Girls Nashik Nehal 7001305949 Independent Escort Service NashikCall Girls in Nagpur High Profile
 
result management system report for college project
result management system report for college projectresult management system report for college project
result management system report for college projectTonystark477637
 
UNIT-II FMM-Flow Through Circular Conduits
UNIT-II FMM-Flow Through Circular ConduitsUNIT-II FMM-Flow Through Circular Conduits
UNIT-II FMM-Flow Through Circular Conduitsrknatarajan
 
BSides Seattle 2024 - Stopping Ethan Hunt From Taking Your Data.pptx
BSides Seattle 2024 - Stopping Ethan Hunt From Taking Your Data.pptxBSides Seattle 2024 - Stopping Ethan Hunt From Taking Your Data.pptx
BSides Seattle 2024 - Stopping Ethan Hunt From Taking Your Data.pptxfenichawla
 
Introduction to IEEE STANDARDS and its different types.pptx
Introduction to IEEE STANDARDS and its different types.pptxIntroduction to IEEE STANDARDS and its different types.pptx
Introduction to IEEE STANDARDS and its different types.pptxupamatechverse
 
Processing & Properties of Floor and Wall Tiles.pptx
Processing & Properties of Floor and Wall Tiles.pptxProcessing & Properties of Floor and Wall Tiles.pptx
Processing & Properties of Floor and Wall Tiles.pptxpranjaldaimarysona
 
MANUFACTURING PROCESS-II UNIT-2 LATHE MACHINE
MANUFACTURING PROCESS-II UNIT-2 LATHE MACHINEMANUFACTURING PROCESS-II UNIT-2 LATHE MACHINE
MANUFACTURING PROCESS-II UNIT-2 LATHE MACHINESIVASHANKAR N
 
Top Rated Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...
Top Rated  Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...Top Rated  Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...
Top Rated Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...Call Girls in Nagpur High Profile
 
Call Girls in Nagpur Suman Call 7001035870 Meet With Nagpur Escorts
Call Girls in Nagpur Suman Call 7001035870 Meet With Nagpur EscortsCall Girls in Nagpur Suman Call 7001035870 Meet With Nagpur Escorts
Call Girls in Nagpur Suman Call 7001035870 Meet With Nagpur EscortsCall Girls in Nagpur High Profile
 
KubeKraft presentation @CloudNativeHooghly
KubeKraft presentation @CloudNativeHooghlyKubeKraft presentation @CloudNativeHooghly
KubeKraft presentation @CloudNativeHooghlysanyuktamishra911
 
Porous Ceramics seminar and technical writing
Porous Ceramics seminar and technical writingPorous Ceramics seminar and technical writing
Porous Ceramics seminar and technical writingrakeshbaidya232001
 
Introduction and different types of Ethernet.pptx
Introduction and different types of Ethernet.pptxIntroduction and different types of Ethernet.pptx
Introduction and different types of Ethernet.pptxupamatechverse
 

Recently uploaded (20)

The Most Attractive Pune Call Girls Budhwar Peth 8250192130 Will You Miss Thi...
The Most Attractive Pune Call Girls Budhwar Peth 8250192130 Will You Miss Thi...The Most Attractive Pune Call Girls Budhwar Peth 8250192130 Will You Miss Thi...
The Most Attractive Pune Call Girls Budhwar Peth 8250192130 Will You Miss Thi...
 
Online banking management system project.pdf
Online banking management system project.pdfOnline banking management system project.pdf
Online banking management system project.pdf
 
(ANJALI) Dange Chowk Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
(ANJALI) Dange Chowk Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...(ANJALI) Dange Chowk Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
(ANJALI) Dange Chowk Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
 
Call for Papers - African Journal of Biological Sciences, E-ISSN: 2663-2187, ...
Call for Papers - African Journal of Biological Sciences, E-ISSN: 2663-2187, ...Call for Papers - African Journal of Biological Sciences, E-ISSN: 2663-2187, ...
Call for Papers - African Journal of Biological Sciences, E-ISSN: 2663-2187, ...
 
UNIT-III FMM. DIMENSIONAL ANALYSIS
UNIT-III FMM.        DIMENSIONAL ANALYSISUNIT-III FMM.        DIMENSIONAL ANALYSIS
UNIT-III FMM. DIMENSIONAL ANALYSIS
 
VIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 Booking
VIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 BookingVIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 Booking
VIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 Booking
 
The Most Attractive Pune Call Girls Manchar 8250192130 Will You Miss This Cha...
The Most Attractive Pune Call Girls Manchar 8250192130 Will You Miss This Cha...The Most Attractive Pune Call Girls Manchar 8250192130 Will You Miss This Cha...
The Most Attractive Pune Call Girls Manchar 8250192130 Will You Miss This Cha...
 
College Call Girls Nashik Nehal 7001305949 Independent Escort Service Nashik
College Call Girls Nashik Nehal 7001305949 Independent Escort Service NashikCollege Call Girls Nashik Nehal 7001305949 Independent Escort Service Nashik
College Call Girls Nashik Nehal 7001305949 Independent Escort Service Nashik
 
result management system report for college project
result management system report for college projectresult management system report for college project
result management system report for college project
 
UNIT-II FMM-Flow Through Circular Conduits
UNIT-II FMM-Flow Through Circular ConduitsUNIT-II FMM-Flow Through Circular Conduits
UNIT-II FMM-Flow Through Circular Conduits
 
BSides Seattle 2024 - Stopping Ethan Hunt From Taking Your Data.pptx
BSides Seattle 2024 - Stopping Ethan Hunt From Taking Your Data.pptxBSides Seattle 2024 - Stopping Ethan Hunt From Taking Your Data.pptx
BSides Seattle 2024 - Stopping Ethan Hunt From Taking Your Data.pptx
 
(INDIRA) Call Girl Aurangabad Call Now 8617697112 Aurangabad Escorts 24x7
(INDIRA) Call Girl Aurangabad Call Now 8617697112 Aurangabad Escorts 24x7(INDIRA) Call Girl Aurangabad Call Now 8617697112 Aurangabad Escorts 24x7
(INDIRA) Call Girl Aurangabad Call Now 8617697112 Aurangabad Escorts 24x7
 
Introduction to IEEE STANDARDS and its different types.pptx
Introduction to IEEE STANDARDS and its different types.pptxIntroduction to IEEE STANDARDS and its different types.pptx
Introduction to IEEE STANDARDS and its different types.pptx
 
Processing & Properties of Floor and Wall Tiles.pptx
Processing & Properties of Floor and Wall Tiles.pptxProcessing & Properties of Floor and Wall Tiles.pptx
Processing & Properties of Floor and Wall Tiles.pptx
 
MANUFACTURING PROCESS-II UNIT-2 LATHE MACHINE
MANUFACTURING PROCESS-II UNIT-2 LATHE MACHINEMANUFACTURING PROCESS-II UNIT-2 LATHE MACHINE
MANUFACTURING PROCESS-II UNIT-2 LATHE MACHINE
 
Top Rated Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...
Top Rated  Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...Top Rated  Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...
Top Rated Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...
 
Call Girls in Nagpur Suman Call 7001035870 Meet With Nagpur Escorts
Call Girls in Nagpur Suman Call 7001035870 Meet With Nagpur EscortsCall Girls in Nagpur Suman Call 7001035870 Meet With Nagpur Escorts
Call Girls in Nagpur Suman Call 7001035870 Meet With Nagpur Escorts
 
KubeKraft presentation @CloudNativeHooghly
KubeKraft presentation @CloudNativeHooghlyKubeKraft presentation @CloudNativeHooghly
KubeKraft presentation @CloudNativeHooghly
 
Porous Ceramics seminar and technical writing
Porous Ceramics seminar and technical writingPorous Ceramics seminar and technical writing
Porous Ceramics seminar and technical writing
 
Introduction and different types of Ethernet.pptx
Introduction and different types of Ethernet.pptxIntroduction and different types of Ethernet.pptx
Introduction and different types of Ethernet.pptx
 

Frameworkless Web Development in Clojure

  • 1. Frameworkless Web Development in Clojure Andreas ’Kungi’ Klein 24.01.2015 Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 1 / 21
  • 2. Outline 1 Web programming in Clojure 2 HTTP Abstraction 3 Routing 4 HTML Templating 5 Authentication 6 Conclusion 7 Bibliography Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 2 / 21
  • 3. Web programming in Clojure What’s I like? No dominant web frameworks No framework dependent paradigms Just plain clojure data structures and functions The full power of clojure is available in every ”step” Web programming from the bottom up Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 3 / 21
  • 4. What’s nice to have for web programming? The typical web framework offers: Web Server / HTTP abstraction Middlewares Session CSRF Protection Request Routing HTML Templating Authentication (Database abstraction) (Communication with the frontend) Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 4 / 21
  • 5. Clojure’s libraries Feature Library HTTP Abstraction Ring Middlewares Ring Routing Clout / Compojure HTML Templating Hiccup / Enlive Authentication Friend Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 5 / 21
  • 6. What is Ring? Ring is the most widely used Clojure interface between web servers and web applications. Similar technologies in other languages include Plack (Perl) Rack (Ruby) Clack (Common Lisp) WSGI (Python) Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 6 / 21
  • 7. Ring concepts Client Adapter HTTP Request Ring Request Middleware Ring Request Handler Adapter HTTP Response Ring Response Middleware Ring Response Requests, Responses, Middlewares, Handlers, Adapters Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 7 / 21
  • 8. Ring example Example project.clj :dependencies [[org.clojure/clojure "1.6.0"] [ring/ring-core "1.3.2"]] :plugins [[lein-ring "0.9.1"]] :ring {:handler ring-example.core/handler} Example Ring handler (ns ring-example.core) (defn handler [request] {:status 200 :headers {"Content-Type" "text/html"} :body "Hello World"}) Start with lein ring server Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 8 / 21
  • 9. Request / Response Requests and responses are maps (see ring spec) (require '[ring.mock.request :as mock]) (mock/request :get "/hallo") => {:server-port 80 :server-name "localhost" :remote-addr "localhost" :uri "/hallo" :query-string nil :scheme :http :request-method :get :headers {"host" "localhost"}} (handler (mock/request :get "/hallo")) => {:headers {"Content-Type" "text/html"} :status 200 :body "Hello World"} Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 9 / 21
  • 10. Middleware A middleware is a higher order function that enhances a handler. The first argument is a handler-function and the middleware itself returns a handler function. (defn wrap-content-type [handler content-type] (fn [request] (let [response (handler request)] (assoc-in response [:headers "Content-Type"] content-type)))) Usage (def app (-> handler (wrap-content-type "text/html"))) Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 10 / 21
  • 11. Adapter Adapters translate from a concrete web server to ring requests and responses. For example ring.adapter.jetty as the name suggests connects ring to jetty. This is where most of the magic happens: (defn- proxy-handler "Returns an Jetty Handler implementation for the given Ring handler." [handler] (proxy [AbstractHandler] [] (handle [_ ^Request base-request request response] (let [request-map (servlet/build-request-map request) response-map (handler request-map)] (when response-map (servlet/update-servlet-response response response-map) (.setHandled base-request true)))))) Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 11 / 21
  • 12. Clout Clout is an HTTP matching library using the same syntax as Rails or Sinatra. (require '[clout.core :as clout]) (require '[ring.mock.request :as mock]) (clout/route-matches "/article/:title/author/:name" (mock/request :get "/article/clojure/author/rich")) => {:title "clojure" :name "rich"} (clout/route-matches "/article/:title" (mock/request :get "schnuff-schnuff")) => nil Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 12 / 21
  • 13. Compojure Most of the time Clout is used through compojure. Compojure combines ring and clout through a concise syntax. (require '[compojure.core :refer [GET POST defroutes]]) (require '[ring.util.response :refer [redirect-after-post]]) (defroutes app (GET "/article/:title" [title] (str "Found article " title)) (POST "/article" request (let [article (create-article (:body request))] (reqirect-after-post (str "/article/" (:id article)))))) Compojure routes are ring handlers. Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 13 / 21
  • 14. Hiccup Hiccup is a literal translation from HTML to clojure vectors and maps. (use 'hiccup.page) (html5 [:head [:title "How much do I love clojure?"]] [:body [:h1 "Very Much!"]]) => "<!DOCTYPE html> <html> <head><title>How much do I love clojure?</title></head> <body><h1>Very Much!</h1></body> </html>" It also provides some CSS selector like shortcuts. [:div#id.class-1.class2 "Schnuff!"] => "<div class="class-1 class2" id="id">Schnuff!</div>" Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 14 / 21
  • 15. Enlive A completely different strategy to HTML templating is provided by Enlive. It works with selectors and transformations. Suppose the following HTML exists in test.html: <!DOCTYPE html> <html lang="en"> <head><title>This is a title placeholder</title></head> <body><ul></ul></body> </html> (use '[net.cgrand.enlive-html]) (deftemplate main-template "test.html" [foo] [:head :title] (content (str "Enlive starter kit: " foo)) [:body :ul] (do-> (add-class "item-list") (append (html [:li "Item 1"])) (append (html [:li "Item 2"])))) deftemplate creates a function which returns html. Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 15 / 21
  • 16. Friend Friend calls itself an ”extensible authentication and authorization library for Clojure Ring web applications and services.” Works very well with ring/compojure Provides role based authentication Friend contains two mayor concepts Credential functions Authentication workflows (e.g. OAuth, HTTP Basic Auth, Login Form, …) Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 16 / 21
  • 17. Credential function example A credential function returns either nil or a map representing the credentials like {:username "joe" :app.foo/passphrase "bcrypt hash"} (defn bcrypt-credential-fn [load-credentials-fn {:keys [username password]}] (when-let [creds (load-credentials-fn username)] (let [password-key (or (-> creds meta ::password-key) :password)] (when (bcrypt-verify password (get creds password-key)) (dissoc creds password-key))))) Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 17 / 21
  • 18. Workflow example A workflow function either returns an authorization map containing the users credentials or it delivers an error page depending on the kind of workflow. The interactive-form workflow for example delivers a login page in case of failure. See the following simplified example from the friend source: (defn http-basic [& {:keys [credential-fn realm] :as basic-config}] (fn [{{:strs [authorization]} :headers :as request}] (when (and authorization (re-matches #"s*Basics+(.+)" authorization)) (if-let [[[_ username password]] (extract-username-password ...)] (if-let [user-record ((gets :credential-fn basic-config (::friend/auth-config request)) ^{::friend/workflow :http-basic} {:username username, :password password})] (make-auth user-record {::friend/workflow :http-basic ::friend/redirect-on-auth? false ::friend/ensure-session false}) (http-basic-deny realm request)) {:status 400 :body "Malformed Authorization header for HTTP Basic authentication."})))) Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 18 / 21
  • 19. Putting it together (ns your.ring.app (:require [cemerick.friend :as friend] (cemerick.friend [workflows :as workflows] [credentials :as creds]))) ;; a dummy in-memory user "database" (def users {"root" {:username "root" :password (creds/hash-bcrypt "admin_password") :roles #{::admin}} "jane" {:username "jane" :password (creds/hash-bcrypt "user_password") :roles #{::user}}}) (def ring-app ;; ... assemble routes however you like ... ) (def secured-app (-> ring-app (friend/authenticate {:credential-fn (partial creds/bcrypt-credential-fn users) :workflows [(workflows/interactive-form)]}) ;; ...required Ring middlewares ... )) Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 19 / 21
  • 20. Frameworkless Web Development What’s great about Frameworkless? Small libraries can be composed easily Communication between these libraries is easy because plain old clojure data structures are used Systems become easier through separation of concerns Andreas ’Kungi’ Klein Frameworkless Web Development in Clojure 24.01.2015 20 / 21