Наши партнеры

UnixForum





Библиотека сайта rus-linux.net

Фреймворк Yesod

Глава 22 из книги "Архитектура приложений с открытым исходным кодом", том 2.

Оригинал: Yesod
Автор: Michael Snoyman
Перевод: Н.Ромоданов

22.5. Yesod

Если мы посмотрим на типичную парадигму «Модель-Представление-Контроллер» («Model-View-Controller» - MVC), то Persistent является моделью, а Shakespeare является преставлением. Тогда все, что остается Yesod, это выступать в роли контроллера.

Самая основная особенность Yesod это - маршрутизация. Она позволяет иметь декларативный синтаксис и типобезопасную диспетчеризацию обращений. На основе этого в Yesod создано много других возможностей: генерация потокового контента, виджеты, интернационализация, статические файлы, формы и аутентификация. Но основной особенностью, которая добавлена в Yesod, в действительности является маршрутизация.

Это многоуровневый подход облегчает пользователям обмениваться различными компонентами системы. Некоторых не интересует использование Persistent. Для них в ядре системы нет ничего, даже упоминающего о Persistent. Точно также, хотя аутентификация и сохранение файлов со статистикой используются часто, эти функции нужны не каждому.

С другой стороны, многие пользователи хотят пользоваться всеми этими функциями. И делают это, включая все оптимизации, имеющиеся в в Yesod, что не всегда просто. Чтобы упростить процесс, в Yesod также предлагается специальный инструментальный набор, с помощью которого настраивается базовая часть сайта с наиболее часто используемыми возможностями.

Маршруты

Учитывая то, что маршрутизация на самом деле является основной функцией Yesod, давайте начнем с нее. Синтаксис маршрутизации очень прост: шаблон ресурса, имя и методы запросов. Например, простой блог-сайт может выглядеть следующим образом:

/ HomepageR GET
/add-entry AddEntryR GET POST
/entry/#EntryId EntryR GET

В первой строке определена домашняя страница. Здесь говорится - «Я представляю собой корневой каталог домена, мое имя HomepageR и я отвечаю на запросы GET». Завершающий символ «R» в именах ресурсов является просто общепринятым соглашением, в нем не закладывается никакого общего смысла, кроме как просигнализировать разработчику о том, что нечто является маршрутом.

Во второй строке определена страница добавочной записи. На этот раз мы отвечаем на оба запроса GET и POST. Вы удивитесь, почему в Yesod, в отличие от большинства фреймворков, требуется, чтобы вы явно указывали методы ваших запросов. Причина в том, что Yesod старается придерживаться принципов RESTful настолько, насколько это возможно, а запросы GET и POST по смыслу действительно очень различные. Мало того, что вы устанавливаете эти два метода по отдельности, затем вы отдельно определяете для них функции обработчиков. В действительности, это дополнительная функция в Yesod. Если вы хотите, вы можете убрать из списка названия методов и функции ваших обработчиков будут использоваться для всех методов запроса.

Третья строка немного интереснее. После второго «слеша» у на есть #EntryId. Таким образом определяется параметр EntryId. Мы уже ссылались на эту функцию в разделе о компоненте Persistent: Yesod будет автоматически строить компонент, представляющий собой путь к соответствующему значению ID. Предположим, что на серверной стороне у нас используется SQL (о Mongo поговорим позже), и если пользователь сделает запрос /entry/5, то функции обработчика будет вызвана с аргументом EntryId 5. Но если пользователь сделает запрос /entry/some-blog-post, то Yesod вернет значение 404.

Очевидно, что это также возможно в большинстве других веб фреймворков. Например, в подходе, применяемом в Django, можно использовать регулярные выражения для проверки соответствия маршрутов, например, r"/entry/(\d+)". Однако подход, применяемый в Yesod, имеет ряд преимуществ:

  • Ввод «EntryId» семантически гораздо более удобен/дружественен для разработчика , чем регулярное выражение.
  • С помощью регулярных выражений нельзя выразить все (или по крайней мере, нельзя это сделать лаконично). В Yesod мы можем использовать /calendar/#Day; вы хотите набрать регулярное выражение для того, чтобы сравнивать даты в ваших маршрутах?
  • Yesod также автоматически находит для нас пути. В случае использования календаря, наша функция обработки получит значение Day. В эквиваленте в Django, функция получит кусок текста, по которому нужно будет выполнять поиск самостоятельно. Это утомительно, это требуется каждый раз повторять и это неэффективно.
  • До сих пор мы предполагали, что идентификатор базы данных ID является простой строкой цифр. Но что, если он более сложен? В MongoDB, например, используются идентификаторы GUID. В Yesod ваш запрос #EntryId все равно будет работать, а система типов проинструктирует Yesod, как анализировать маршрут. В системе регулярных выражений, вам придется пройти по всем вашим маршрутам и заменить \d+ на чудовищно сложное регулярное выражение, необходимое для сравнения идентификаторов GUID.

Адреса типобезопасных URL

Такой подход к маршрутизации порождает одну из самых мощных функций Yesod: типобезопасные адреса URL. Вместо того, чтобы объединять вместе части текста со ссылками, обозначающими маршрут, каждый маршрут в вашем приложении может быть представлен с помощью значения языка Haskell. Благодаря этому сразу исчезает большое количество ошибок 404 Not Found (404 Не найдено): просто невозможно получить неправильный URL. (Все еще можно сформировать URL, который приведет к ошибке 404, например, из-за ссылки на несуществующее сообщение в блоге. Тем не менее, все адреса будут сформированы правильно).

Так как же это магия работает? В каждом сайте есть тип данных route, и для каждого шаблона ресурсов есть свой собственный конструктор. Для нашего предыдущего примера мы получим что-то вроде следующего:

data MySiteRoute = HomepageR
                 | AddEntryR
                 | EntryR EntryId

Если вы хотите перейти по ссылке на домашнюю странице, вы используете HomepageR. Чтобы разместить ссылку на конкретную запись, вы должны использовать конструктор EntryR с параметром EntryId. Например, чтобы создать новую запись и перейти на нее, вы могли бы написать:

entryId <- insert (Entry "My Entry" "Some content")
redirect RedirectTemporary (EntryR entryId)

Во всех языках Hamlet, Lucius и Julius есть встроенная поддержка таких типобезопасный адресов URL. Внутри шаблона на языке Hamlet вы можете легко создать ссылку на страницу с дополнительной записью:

<a href=@{AddEntryR}>Create a new entry.

Что же самое интересное? Точно также, как и в случае с сущностями Persistent, компилятор обеспечит вам полный порядок. Если вы поменяли какие-либо из ваших маршрутов (например, вы хотите включить в число ваших маршрутов год и месяц), Yesod заставит вас повсюду в коде обновить каждую ссылку.


Далее: Обработчики и виджеты