Веб-приложения на Clojure

от автора

На Хабре не так уж и много статей о Clojure, и это печально, намерен это исправить. Ниже я расскажу об отличном на мой субъективный взгляд инструменте — языке программирования Clojure и его библиотеках для создания веб-приложений.

В этой статье не будет сравнения Clojure с другими языками, так как отталкиваясь от скромного опыта сравнивать не с чем.

Основная информация о Clojure

Clojure — это мультипарадигмальный язык программирования общего назначения поощряющий функциональное программирование. Основой этого языка и его синтаксиса является Lisp и его S-expressions. В отличие от Lisp’a Clojure включает и другие типы данных (коллекции), такие как: векторы, ассоциативные массивы, множества и очень удобные в использовании ключевые-слова.
Код компилируется JVM в java байт-код, что позволяет развертывать приложения на большом количестве платформ и само-собой использовать все доступные Java библиотеки.

В интернетах полно информации о структурах Clojure, поэтому я пропущу описание оных.

Комюнити

Нельзя не сказать о сложившимся вокруг этого языка программирования сообществе, которое не столь огромно, но очень дружелюбно к новичкам и не только, они с готовностью помогают решать возникшие проблемы. Имеется большое количество видеоматериалов по самым разным аспектам использования Clojure, только вот практически все они на английском языке (рай для самореализации переводчиков). В конце статьи будут ссылки.

Leiningen

Альтернатива Maven. Используется для управления зависимостями проекта, настройками библиотек и глобальными настройками проекта. Проекты на Clojure создаются с помощью
команды:
lein new <название шаблона проекта (app|compojure|luminus…)> <название проекта>
Это создает каталог с проектом Clojure, имеющую все необходимые файлы и каталоги. И конечно же создает файл project.clj в котором и подключаются все библиотеки и выставляются глобальные настройки: библиотек, проекта, компиляции, repl и т.п…

Ring

Ring — представляет из себя слой абстракции над HTTP, предоставляя взаимодействие с ним через простой API. Очень успешно применяется при создании модульных приложений.
Примеры использования, можно увидеть на их странице github (ссылка в конце статьи). Я же использую еще одну абстракцию над Ring, которая на мой взгляд более упрощает работу с маршрутами Ring и называется Compojure.

Compojure

Библиотека для маршрутизации Ring, с её помощью можно удобно упаковывать маршруты и использовать их в handler’e проекта.

Ниже привожу простой пример:

(defroutes auth-routes   ; Очистка сессии   (GET "/logout"         ; Мы можем передать запрос контроллеру        ; полностью        request        (-> logout-controller))    ; Обработчик авторизации через POST запрос   (POST "/login"          ; Или передать определенные параметры         [login password]         (login-controller login password))    ; Авторизация   ; Указан GET запрос и можно вызвать   ; представление страницы напрямую   ; или упаковать все в контроллер    ; из которого будет вызвана функция   ; представления страницы   (GET "/login"        request        (view/login-page))) 

Такое тоже возможно:

(defroutes users-routes    ; Страница просмотра профиля   (GET "/profile/:login"         ; В request в :params уже будет доступно        ; значение login с ключом указанным выше :login        request               ; Синтаксический сахар под названием ->        ; передает первый входящий аргумент        ; функции обработчику.        (-> profile-view-controller-GET))) 

Не стану приводить пример request’a так как вы все прекрасно понимаете как он выглядит. На этом о Compojure закончено.

Buddy

Библиотека для авторизации и аутентификации пользователей. Упаковывает сессии авторизованных пользователей в HTTP заголовок в свой backend, имеет функции для шифрования паролей и т.п…

Пример шифрования пароля:

(buddy.hashers/encrypt "qwerty") 

Пример функции авторизации из моего проекта:

(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 "Проверьте правильность введенных данных")))) 

Так-же позволяет настраивать доступ к страницам в middleware, пример:

(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 шаблонизатор, вдохновленный Django. Позволяет очень гибко работать с данными в HTML шаблонах.

(defn registration-page   "Страница регистрации пользователя"   []   (render "registration.html"         {:foo [1 2 3 4 5]}))) 

И сам шаблон:

<ul>     {% for i in foo %}     {{i}}     {% endfor %} </ul> 

Monger

Библиотека для работы с mongodb, вообще Clojure очень удобный инструмент для работы с базами данных, все благодаря его коллекциям.

Небольшой пример:

(ns test.users.db   (:require monger.joda-time             [monger.collection :as m]             [expertus.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"}) 

Про обилие скобок

Скобок много, нужно привыкнуть, но внимательный человек обратит внимание, что их не больше чем фигурных скобок в том-же JavaScript.

Ссылки на описанные библиотеки

Дополнительные ссылки

На этом пожалуй все, в дальнейших статьях если к ним проявится интерес я расскажу про каждую библиотеку в отдельности, про замечательный веб-сервер immutant, ни и конечно же про ClojureScript который удобно использовать при разработке front-end приложений и компилируется он javascript. Так-же хотелось бы осветить фреймфорк Luminus, который очень сильно помог мне разобраться с веб-разработкой на Clojure. Надеюсь моя, хоть и не всеобъемлющая статья заинтересует вас просмотреть возможности этого замечательного инструмента.

Благодарю, всего вам лучшего!

ссылка на оригинал статьи http://habrahabr.ru/post/263115/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *