В этой статье есть несколько проблем. Помогите улучшить ее или обсудите эти проблемы на странице обсуждения . ( Узнайте, как и когда удалять эти сообщения )
|
Оригинальный автор(ы) | Майкл Снойман |
---|---|
Разработчик(и) | Майкл Снойман и др. |
Первоначальный выпуск | 2010 (2010) |
Стабильный релиз | 1.6.24.5 [1] / 14 сентября 2023 г. (14 September 2023) |
Репозиторий |
|
Написано в | Хаскелл |
Операционная система | Кроссплатформенный |
Доступно в | Английский |
Тип | Веб-фреймворк |
Лицензия | Массачусетский технологический институт |
Веб-сайт | www.yesodweb.com |
Yesod ( IPA: [je'sod] ; иврит : יְסוֺד , «Основание») — это веб-фреймворк на основе языка программирования Haskell для продуктивной разработки типобезопасных, основанных на модели передачи репрезентативного состояния ( REST ) (где унифицированные указатели ресурсов ( URL ) идентифицируют ресурсы, а методы протокола передачи гипертекста (HTTP) идентифицируют переходы), высокопроизводительных веб-приложений, разработанный Майклом Снойманом и др. Это бесплатное программное обеспечение с открытым исходным кодом, выпущенное по лицензии MIT .
Yesod основан на шаблонах для генерации экземпляров для перечисленных сущностей и динамических функций обработки контента с помощью конструкций Template Haskell для размещения шаблонов контента на доменно-специфическом языке (eDSL), называемых QuasiQuotes, где контент транслируется в выражения кода с помощью инструкций метапрограммирования . [2]
Существуют также шаблоны фрагментов языка, подобные веб-подобным , которые допускают интерполяцию выражений кода, что делает их полностью типизированными во время компиляции . [3]
Yesod разделяет свои функции на отдельные библиотеки ( база данных , HTML-рендеринг, формы и т. д.), поэтому функции можно использовать по мере необходимости.
Yesod использует шаблон проектирования программного обеспечения «модель-представление-контроллер» (MVC) для своих пользовательских интерфейсов .
Yesod использует интерфейс веб-приложений (WAI), [4] тип интерфейса прикладного программирования ( API ), для изоляции сервлетов , также известных как веб-приложения, от серверов, с обработчиками для серверных протоколов Common Gateway Interface (CGI), [5] FastCGI , [6] Simple Common Gateway Interface (SCGI), [7] Warp, [8] Launch (открывается как локальный URL-адрес в браузере по умолчанию, закрывая сервер при закрытии окна), [9]
См. ссылку [10] Yesod требует тип данных, который создает экземпляры классов модель–представление–контроллер . Это называется фундаментальным типом. В примере ниже он называется «MyApp».
Модель REST идентифицирует веб-ресурс с веб-путем. Здесь REST-ресурсам присваиваются имена с суффиксом R (например, "HomeR"), и они перечислены в шаблоне описания карты сайта parseRoutes . Из этого списка выводятся имена маршрутов и имена обработчиков отправки.
Yesod использует метапрограммирование Template Haskell для генерации кода из шаблонов во время компиляции, гарантируя, что имена в шаблонах совпадают, а все типы проверяются (например, имена веб-ресурсов и имена обработчиков).
Вставка вызова mkYesod приведет к вызову примитивов Template Haskell для генерации кода [11], соответствующего членам типа маршрута, и экземпляров классов диспетчерского контроллера для отправки вызовов GET для маршрутизации HomeR в процедуру, названную «getHomeR», ожидая существующий обработчик, соответствующий имени.
Пример программы «Hello, World!» на основе интерфейса сервера Common Gateway Interface (CGI) (типы обработчиков изменились, но философия осталась):
{- файл wai-cgi-hello.hs -} {-# ЯЗЫК PackageImports, TypeFamilies, QuasiQuotes, MultiParamTypeClasses, TemplateHaskell, OverloadedStrings #-} import "wai" Network.Wai import "wai-extra" Network.Wai.Handler.CGI ( run ) -- взаимозаменяемый обработчик WAI импорт "yesod" Yesod импорт "yesod-core" Yesod.Handler ( getRequest ) импорт "text" Data.Text ( Текст ) импорт "shakespeare" Text.Cassius ( Цвет ( .. ), colorBlack ) -- данные типа Foundation MyApp = MyApp -- шаблон карты сайта, путь к списку, имя ресурса и методы приняты -- `mkYesod` принимает имя типа основы в качестве параметра для составления имени функций диспетчеризации mkYesod "MyApp" [ parseRoutes | / HomeR GET | ] экземпляр Yesod MyApp -- структурированный шаблон CSS с отступами myStyle :: [ Текст ] → CssUrl url myStyle paramStyle = [ cassius | . box border : 1 px solid # { boxColor } | ] где boxColor = case paramStyle of [ "high-contrast" ] → colorBlack _ → Color 0 0 255 -- структурированный HTML-шаблон с отступами myHtml :: [( Текст , Текст )] → HtmlUrl url myHtml параметры = [ hamlet |
<!-- отступ или его отсутствие под начальными тегами или командами (префикс ' $ ') описывает содержимое или структуру дерева последовательности --> <!-- префиксы '.' или ' # ' в тегах вводят значения атрибутов "class" или "id" в стиле css --> <!-- интерполяция выражений haskell следует синтаксису "шаблонов шекспира" #{ expr } -->< p > Привет, мир! Есть < span . box > #{ length params} параметры </ span > : $ if null params < p > Ничего не перечислить $ else < ul > $ forall param < - params < li > #{ fst param}: #{ snd param}|]
getHomeR :: Handler RepHtml getHomeR = do req <- getRequest let params = reqGetParams req paramStyle <- lookupGetParams "style" defaultLayout $ do -- добавление виджетов в монаду Widget (монаду ''Writer'') setTitle "Yesod example" toWidgetHead $ myStyle paramStyle toWidgetBody $ myHtml params -- существуют варианты функции ''run'' для разных обработчиков WAImain = toWaiApp MyApp >>= запустить
# cgi test export REMOTE_ADDR = 127 .0.0.1 export REQUEST_METHOD = GET export PATH_INFO = / export QUERY_STRING = 'p1=abc;p2=def;style=high-contrast' ./wai-cgi-привет
[10]
См. ссылку [12] [13] Yesod следует репрезентативной модели передачи состояния доступа к веб-документам, идентифицируя документы и каталоги как ресурсы с помощью конструктора Route, именованного с заглавным суффиксом R (например, HomeR).
Возможен захват сегмента URL в качестве параметра с указанием префикса «#» для захвата одного сегмента или «*» для захвата нескольких сегментов, за которым следует тип параметра.
-- учитывая тип фундамента MyAppmkYesod "MyApp" [ parseRoutes | / HomeR -- методы http не указаны: принимаются все методы / blog BlogR GET POST -- префикс '#' указывает сегмент пути как параметр обработчика маршрута / article /# ArticleId ArticleR GET PUT -- префикс '*' указывает параметр как последовательность частей пути / branch /* Тексты BranchR GET -- для упрощения грамматики составные типы должны использовать псевдоним, например, тип Texts для ''[Text]'' | ]
Данные Маршрут MyApp = HomeR -- в шаблонах упоминаются как: @{HomeR} | BlogR -- в шаблонах: @{BlogR} | ArticleR ArticleId -- в шаблонах: @{ArticleR myArticleId} | BranchR Тексты -- в шаблонах: @{BranchR myBranchSegments}
-- для "/ HomeR" -- http-методы не указаны ⇒ только один обработчик с префиксом ''handler'' handlerHomeR :: HasReps t ⇒ Handler t -- для "/blog BlogR GET POST" getBlogR :: HasReps t ⇒ Обработчик t postBlogR :: HasReps t ⇒ Обработчик t -- для "/article/#ArticleId ArticleR GET PUT" getArticleR :: HasReps t ⇒ ArticleId → Handler t putArticleR :: HasReps t ⇒ ArticleId → Handler t
См. ссылку [12]
См. ссылку [14] Плагины аутентификации: OpenID , BrowserID , Email, GoogleEmail, HashDB, RpxNow. [15]
См. ссылку [17] Серверные части сеанса: ClientSession [18] (он сохраняет сеанс в cookie-файле), ServerSession [19] [20] (он сохраняет большую часть данных сеанса на сервере)
Сообщение об успешном выполнении, неудаче или индикативное сообщение может быть сохранено ( setMessage ) в сеансе и будет показано, если оно существует, процедурой default_layout через default_layout.hamlet
шаблон, очищаясь при консультации. [21]
Общие URL-префиксы подсайтов для рабочих процессов, обслуживания файлов или разбиения сайта. См. ссылку [22] [23]
Встроенные дочерние сайты: Статические, [24] [25] Авторизация [26]
См. ссылку [27]
Тип Form здесь — это объект, который используется в контроллере для разбора и обработки ввода пользователя в поля формы и создания пары (FormResult, Widget), где виджет содержит макет следующего отображения формы с сообщениями об ошибках и отметками. Его также можно использовать для создания новой формы с пустыми полями или значениями по умолчанию.
Тип формы принимает форму функции фрагмента HTML, встраиваемого в представление, которое будет содержать скрытые поля в целях безопасности.
Объект формы генерируется из аппликационной – монадической композиции полей для комбинированного последовательного анализа входных данных полей.
Существует три типа форм:
Генераторы полей, имена которых состоят из начального типа формы , (a|m|i)
за которым следует (req|opt){- required or optional -}
, имеют компонент fieldParse и компонент fieldView. [28]
runForm{Post|Get}
запускает парсеры полей для входных данных полей формы и генерирует пару (FormResult, Widget) из представлений, предлагая новый виджет формы с полученными значениями полей формы в качестве значений по умолчанию. Суффикс функции — это метод http, используемый при отправке формы.generateForm{Post|Get}
игнорирует вводимые данные от клиента и генерирует пустой или стандартный виджет формы. [29]Фактические параметры и типы функций изменились в версиях Yesod. Проверьте книгу Yesod и сигнатуры библиотек.
Вся магия кроется в экземпляре Applicative типа данных FormResult , где (<*>) собирает сообщения об ошибках для случая значений результата [30]FormFailure [textErrMsg]
Монадические формы допускают свободную компоновку и лучшую обработку элементов hiddenField . [27]
Образец формы Аппликации [31] :
-- запись для данных полей нашей формы Person = Person { personName :: Text , personAge :: Int , personLikings :: Maybe Text } -- тип Form имеет дополнительный параметр для встраиваемого фрагмента HTML, содержащего скрытое поле токена CSRF для типа безопасности Form sub master x = Html → MForm sub master ( FormResult x , Widget ) {- -- для сообщений в функциях проверки: @param master: экземпляр yesod для использования в renderMessage (возврат из getYesod обработчика) @param languages: языки страниц для использования в renderMessage-- необязательная запись по умолчанию: @param mbPersonDefaults: просто defaults_record или ничего для пустой формы -}personForm :: MyFoundationType → [ Текст ] → Maybe Person → Подчиненный мастер формы Person {- ''aopt'' (необязательное поле компонента AForm) для полей "Maybe", ''areq'' (обязательное поле компонента AForm) вставит атрибут "required" -} master personForm languages mbPersonDefaults = renderTable $ Person <$> areq textField fldSettingsName mbNameDefault <*> areq customPersonAgeField fldSettingsAge mbAgeDefault <*> aopt textareaField fldSettingsLikings mbLikingsDefault где mbNameDefault = fmap personName mbPersonDefaults mbAgeDefault = fmap personAge mbPersonDefaults mbLikingsDefault = fmap personLikings mbPersonDefaults -- "fieldSettingsLabel" возвращает начальную запись fieldSettings -- с недавних пор запись "FieldSettings" можно определить из метки String, поскольку она реализует IsString fldSettingsName = ( fieldSettingsLabel MsgName ) { fsAttrs = [( "maxlength" , "20" )]} fldSettingsAge = fieldSettingsLabel MsgAge fldSettingsLikings = ( fieldSettingsLabel MsgLikings ) { fsAttrs = [( "cols" , "40" ),( "rows" , "10" )]} customPersonAgeField = проверка validateAge intField validateAge y | y < 18 = Левый $ renderMessage основные языки MsgUnderAge | в противном случае = Правый y
Показанные типы соответствуют более старой версии, но философия сохраняется.
Монада Handler возвращает содержимое в одном или нескольких форматах как компоненты типов, реализующих класс HasReps [32] { RepHtml, RepJson, RepXml, RepPlain , дуальный RepHtmlJson , пара или список пар , ..}. [33] [34] Примеры Json: [35] [36] [37][(ContentType, Content)]
Реализация HasReps по умолчанию ChooseRep выбирает представление документа, которое будет возвращено , в соответствии со списком предпочтительных типов содержимого заголовка принятия клиента . [32]
Монада Widget [39] , основанная на монаде Writer [40] и аргументе defaultLayout , облегчает объединение виджетов.
[qq| ... |]
«$» предваряет строки логических утверждений.
Автоматические закрывающие теги генерируются только для тега в начальной позиции строки.
toWidget [hamlet| $ doctype 5 < html > <!-- автоматически закрывается только тег в начале строки --> <!-- префиксы '.' или ' # ' в тегах вводят имена классов/идентификаторов в стиле CSS --> <!-- префикс ":boolVar:" в атрибутах делает их условно сгенерированными --> <!-- интерполяция выражений Haskell следует синтаксису "шекспировских шаблонов", введенному в одноименном разделе --> <head> <title> #{ pageTitle } - Мой сайт < link rel = stylesheet href = @ { Stylesheet_route } > <body> <header> ^ { headerTemplate } < section #mySectionId > <p> < span.titleClass > _ { MsgArticleListTitle } </span> $ if null articles < p : isRed : style = " color : red " > _ { MsgSorryNoArticles } $ else <ul> $ forall art < - articles <li> # { articleNumber art } .- # { articleTitle art } <footer> ^ { footerTemplate } |]
См. ссылку [42] Это шаблоны просмотра содержимого, которые следуют общему шаблону подстановки выражений кода в фигурных скобках с различными префиксами символов для ссылки
^{...}
^{template params}
,@{...}
@{HomeR}
,_{...}
_{MsgMessageLabel params}
#{...}
#{haskell_expression}
тип которого должен быть конвертируемым<isoLanguage>
(в файлах ".msg") с интерполяциями параметров тип выражения должен быть экземпляром Text.Shakespeare.I18N.ToMessage [47]Использование неанглийского текста в выражениях требует использования типа Text, поддерживающего Unicode , поскольку компилятор Glasgow Haskell (GHC) для типа String отображает не- ASCII- символы как экранированные числовые коды.
См. ссылку [57]
Сообщения приложения Yesod локализуются ( i18n ). Они должны храниться в папке сообщений , в файлах, названных на основе ISO , как <iso-language>.msg
Записи сообщений следуют шаблону EBNF :
-- EBNF: идентификатор, {' ', параметр, '@', тип}, ":", текст с интерполяциями ArticleUnexistent param @ Int64 : несуществующая статья # { param }
-- в коде myMsg :: MyAppMessage -- тип данных, добавляющий "Message" к базовому типу myMsg = MsgArticleUnexistent myArticleId -- конструктор, добавляющий "Msg" к метке msg. -- в шаблонах виджетов _ { MsgArticleUnexistent myArticleId }
Фактическая поддержка i18n отсутствует в шаблоне стекового приложения. Необходимо добавить в файл "Foundation.hs", чтобы получить экземпляры сообщений. [58]mkMessage "MyApp" messagesFolder isoLangDefault
Например, количество посетителей. См. ссылку [62]
Имеется первоклассная поддержка PostgreSQL , SQLite , MongoDB , CouchDB и MySQL , а также экспериментальная поддержка Redis . [63]
Макет базы данных описывается в шаблоне, в котором перечислены сущности, поля и ограничения. [66]
share [ mkPersist sqlSettings , mkMigrate "migrateAll" -- генерирует процедуру миграции с указанным именем ] [ persist | Пользователь -- имя таблицы и тип записи сущности -- неявный автоинкрементный столбец "id" в качестве первичного ключа, типизированный UserId ident Text -- ссылается на столбец таблицы БД "ident"; -- генерирует поле записи, добавляя к имени таблицы префикс "userIdent" password Text Maybe -- Maybe указывает на поле, допускающее значение NULL UniqueUser ident -- уникальное ограничение с разделителем-пробелом. последовательность полей Email -- имя таблицы и тип записи сущности -- неявный автоинкрементный столбец "id" в качестве первичного ключа, типизированный EmailId email Text user UserId -- внешний ключ путем указания других таблиц EntityField types verkey Text Maybe newlyAddedColumn Текст "default='sometext'::character variationing" -- ограничение по умолчанию на уровне SQL UniqueEmail адрес электронной почты – уникальное ограничение | ]
Пример для постоянных запросов rawSQL и Esqueleto . [71]
Следующие пакеты являются частью yesod-platform : [72]
Новые приложения Yesod генерируются из шаблонов инструмента HaskellStack [76] , заменяя предыдущую команду «yesod init».
Имена шаблонов приложений на основе стека начинаются с префикса yesod, например «yesod-{minimal | postgres | sqlite | mysql | mongo | ...}»
yesod devel
запускается с сайта проекта, перекомпилирует и перезапускает проект при каждом изменении дерева файлов.yesod add-handler
добавляет новый обработчик и модуль в проект, добавляя пункт импорта для обработчика в модуль «Приложение».См. ссылки. [78] [79] [80]
Keter — это процесс как услуга, которая управляет развертыванием и перезапуском серверов веб-приложений Yesod , а также созданием базы данных для PostgreSQL для каждого веб-приложения .
Консольная команда yesod keter
упаковывает веб-приложение в пакет keter для загрузки в папку keter с именем «incoming».
Keter отслеживает папку «incoming» и распаковывает приложение во временную папку, затем назначает веб-приложению порт для прослушивания и запускает его.
Первоначально он работал с Nginx в качестве обратного прокси-сервера (Keter версии 0.1*), добавляя записи виртуального сервера в свою конфигурацию и заставляя Nginx перезагружать его, но теперь Keter сам предоставляет собственную функциональность обратного прокси-сервера , устраняя зависимость от Nginx и выступая в качестве основного веб-сервера. [81]
Старая документация (на основе Nginx). [82] [83]
См. ссылку [84] [85] [86]