📜 ⬆️ ⬇️

Clojure Web Applications

On Habré there are not so many articles about Clojure, and this is sad, I intend to fix it. Below I will talk about a tool that is different in my subjective opinion - Clojure programming language and its libraries for creating web applications.

In this article, there will be no comparison of Clojure with other languages, since, starting from modest experience, there is nothing to compare with.

Clojure's Basic Information

Clojure is a general purpose multiparadigm programming language that promotes functional programming. The basis of this language and its syntax is Lisp and its S-expressions. Unlike Lisp, Clojure includes other data types (collections), such as: vectors, associative arrays, sets, and very easy-to-use keyword keywords. Clojure code is compiled into JVM bytecode, which allows you to deploy applications on a large number of platforms and use all available Java libraries on your own.

The Internet is full of information about the structures of Clojure, so I will skip the description of these.
')
Community

It is impossible not to say about the community that has developed around this programming language, which is not so huge, but very friendly to beginners and not only, they readily help solve the problems that have arisen. There is a large number of video materials on various aspects of using Clojure, except that almost all of them are in English (a paradise for translators' self-realization). At the end of the article will be links.

Leiningen

Alternative Maven. Used to manage project dependencies, library settings, and global project settings. Provides console commands for building, testing, compiling, and running applications.

Clojure projects are created using the command: $ lein new <project template name (app | compojure | luminus ...)> <project name>
This creates a directory with a Clojure project that has all the necessary files and directories. And of course, it creates a project.clj file in which all libraries are connected and global settings are set: libraries, project, compilation, repl, etc ...

Example project.clj file:
(defproject test "0.1.0-SNAPSHOT" :description "" :url "http://test.ru" :dependencies [[org.clojure/clojure "1.7.0"] [selmer "0.8.2"] [com.taoensso/timbre "4.0.2"] [com.taoensso/tower "3.0.2"] [markdown-clj "0.9.67"] [environ "1.0.0"] [compojure "1.3.4"] [ring/ring-defaults "0.1.5"] [ring/ring-session-timeout "0.1.0"] [metosin/ring-middleware-format "0.6.0"] [metosin/ring-http-response "0.6.2"] [bouncer "0.3.3"] [prone "0.8.2"] [org.clojure/tools.nrepl "0.2.10"] [buddy "0.6.0"] [com.novemberain/monger "2.0.1"] [org.immutant/web "2.0.2"] [clojure.joda-time "0.6.0"]] :min-lein-version "2.0.0" :uberjar-name "test.jar" :jvm-opts ["-server"] ;;enable to start the nREPL server when the application launches ;:env {:repl-port 7001} :main test.core :plugins [[lein-environ "1.0.0"] [lein-ancient "0.6.5"]] :profiles {:uberjar {:omit-source true :env {:production true} :aot :all} :dev {:dependencies [[ring-mock "0.1.5"] [ring/ring-devel "1.3.2"] [pjstadig/humane-test-output "0.7.0"]] :repl-options {:init-ns test.core} :injections [(require 'pjstadig.humane-test-output) (pjstadig.humane-test-output/activate!)] :env {:dev true}}}) 



Ring

Ring - is a layer of abstraction over HTTP, providing interaction with it through a simple API. Very successfully used to create modular applications.
Examples of use can be seen on their github page (link at the end of the article). I use another Ring abstraction, which in my opinion makes working with Ring routes easier and is called Compojure.

Compojure

The library for Ring routing, with its help, you can conveniently package routes and use them in the project's handler.

I give a simple example:
 (defroutes auth-routes ;   (GET "/logout" ;      ;  request (-> logout-controller)) ;    POST  (POST "/login" ;     [login password] (login-controller login password)) ;  ;  GET     ;    ;      ;      ;   (GET "/login" request (view/login-page))) 



This is also possible:
 (defroutes users-routes ;    (GET "/profile/:login" ;  request  :params    ;  login     :login request ;     -> ;     ;  . (-> profile-view-controller-GET))) 



I will not give an example of request, since you all understand how it looks. This is about Compojure over.

Buddy

Library for authorization and user authentication. It packs sessions of authorized users into the HTTP header in its backend, has functions for encrypting passwords, etc ...

Password encryption example:
 (buddy.hashers/encrypt "qwerty") 


An example of the authorization function from my project:
 (defn login-controller " " [request] (let [ ;     form {:login (get-in request [:form-params "login"]) :password (get-in request [:form-params "password"])} ;     validate (bouncer/validate form valid/login-validator) ;   errors (first validate) return-errors (fn [message] (util/return-messages view/login-page :error-message message :data validate))] ;    (if-not errors ;      (if (true? (db/user-exist? {:login (:login form)})) ;    (let [user (db/get-user {:login (:login form)} [:password])] ;   (if (hashers/check (:password form) (:password user)) (do ;  :visited (db/update-user {:login (:login form)} {:visited (util/date-time)}) ;    (util/create-session request (:login form) "/")) ;     (return-errors " "))) ;     (return-errors "  ")) ;    (return-errors "   ")))) 



Also Buddy allows you to customize access to pages in middleware.

Example:
 (def rules [{:pattern #"^/user/edit$" :handler authenticated-user} (defn on-error [request response] {:status 403 :headers {"Content-Type" "text/html"} :body (str "   " (:uri request) ".<br>" response)}) (defn wrap-restricted [handler] (restrict handler {:handler authenticated? :on-error on-error})) (defn wrap-identity [handler] (fn [request] (binding [*identity* (or (get-in request [:session :identity]) nil)] (handler request)))) (defn wrap-auth [handler] (-> handler wrap-identity (wrap-authentication (session-backend)))) ;   middleware base: (defn wrap-base [handler] (-> handler wrap-dev ;    (wrap-access-rules {:rules rules :on-error on-error}) ;   wrap-auth ;  (wrap-idle-session-timeout {:timeout (* 60 30) :timeout-response (redirect "/")}) wrap-formats (wrap-defaults (-> site-defaults (assoc-in [:security :anti-forgery] false) (assoc-in [:session :store] (memory-store session/mem)))) wrap-servlet-context wrap-internal-error wrap-uri)) 



Selmer

HTML template engine inspired by Django. Allows very flexible work with data in HTML templates.

 (defn registration-page "  " [] (render "registration.html" {:foo [1 2 3 4 5]}))) 


And the template itself:
 <ul> {% for i in foo %} {{i}} {% endfor %} </ul> 


Monger

The library for working with mongodb, in general Clojure is a very convenient tool for working with databases, all thanks to its collections. Monger is a Clojure MongoDB client (the essence of the library), providing high and low level functions for interacting with the MongoDB API. The library is written very succinctly and at the same time provides everything you need to fully use MongoDB in applications. It is impossible not to notice a huge plus - this is a very detailed and detailed documentation on the official site.

A small example:
 (ns test.users.db (:require monger.joda-time [monger.collection :as m] [test.db :refer [db]])) (def collection "users") (defn get-user " " ([query] (m/find-one-as-map db collection query)) ([query fields] (m/find-one-as-map db collection query fields))) ;  : ;     (get-user {:login "test"} [:first-name :last-name]) ;    (get-user {:login "test"}) 



About the abundance of brackets

There are a lot of brackets, you need to get used to it, but an attentive person will notice that there are no more than braces in the same JavaScript.

Links to the described libraries



Additional links



This is probably all, in future articles, if there is interest in them, I will tell about each library separately, about the wonderful web server immutant, and of course about ClojureScript, which is convenient to use when developing front-end applications and compiled into javascript. I would also like to highlight the Luminus framework, which helped me a lot with Clojure web development. I hope my, though not a comprehensive article will interest you to see the possibilities of this wonderful tool.

Thank you all the best!

Source: https://habr.com/ru/post/263115/


All Articles