На Хабре не так уж и много статей о 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/
Добавить комментарий