Scotty — это легковесный движок для создания веб-приложений на языке Haskell. Что-то вроде Cowboy из мира Erlang или Scalatra из мира Scala. Сегодня с помощью Scotty мы прикрутим веб-интерфейс к нашей телефонной книге .

Весь код веб-приложения находится в модуле Phonebook.Interface.HTTP. Как и модуль Phonebook.Interface.CLI, он экспортирует единственную функцию:

main :: IConnection a => a -> IO ( )

Посмотрим на ее код:

import qualified Web . Scotty as Sc
import qualified Phonebook . Storage as St

{- … -}

main conn = Sc . scotty 8080 $ do
Sc . post «/api/v1.0/contacts» ( create conn )
Sc . get «/api/v1.0/contacts» ( read conn )
Sc . put «/api/v1.0/contacts/:cid» ( update conn )
Sc . delete «/api/v1.0/contacts/:cid» ( delete conn )

Не будем заострять внимание на типах использованных здесь функций. Если очень интересно, можете заглянуть в документацию по Scotty, там все есть. Что тут происходит, понятно и без них. Scotty запускается на порту 8080. Также объявляются маршруты/роуты и соответствующие им хэндлеры.

Давайте посмотрим на функцию create:

create conn = do
body <- Sc . jsonData :: Sc . ActionM ( M . Map String String )
success <- withNamePhone body ( n p -> St . create n p conn )
Sc . status $ boolToHttpCode success

Функция jsonData берет тело запроса и пытается декодировать его, как строку с JSON’ом . Здесь после декодирования мы ожидаем получить тип Map String String . Для успешного выполнения запроса пользователь должен передать JSON-объект, значения полей которого представляют собой строки. Если пользователь пошлет невалидный JSON или валидный, но такой, что его не удастся привести к ожидаемому типу, Scotty вернет ошибку 500 Internal Server Error.

Функции withNamePhone и boolToHttpCode определены так:

withNamePhone m action =
case extractNamePhone m of
Nothing -> return False
Just ( name , phone ) -> liftIO $ action name phone

extractNamePhone :: M . Map String String -> Maybe ( String , String )
extractNamePhone m =
M . lookup «name» m >>=
name -> M . lookup «phone» m >>=
phone -> Just ( name , phone )

boolToHttpCode success =
if success then noContent204
else badRequest400

Надеюсь, вы в достаточной мере владеете особой монадической магией, чтобы понять этот код, потому что обсуждение этой магии, пожалуй, представляет собой хорошую тему для целого отдельного поста. Если в двух словах, наше приложение возвращает код 204 No Content, если запись в телефонной книге была успешно создана, и 400 Bad Request, если что-то пошло не так, например, не было указано имя или телефон.

Рассмотрим следующий хэндлер, функцию read:

read conn = do
contacts <- liftIO $ St . read conn
let objects = map toObj contacts
Sc . json $ Array ( V . fromList objects )
where
toObj :: ( St . ContactId , St . Name , St . Phone ) -> Value
toObj ( cid , name , phone ) =
object [ ( «contactId» , Number $ I cid )
, ( «name» , String $ T . pack name )
, ( «phone» , String $ T . pack phone )
]

Здесь мы читаем из базы все имеющиеся контакты, преобразуем их в список JSON-объектов, а затем полученный список преобразуем в JSON-массив, который отдается пользователю. Для работы с JSON в Haskell большой популярностью пользуется пакет aeson. JSON в нем представляется следующим образом:

type Array = Vector Value
type Object = HashMap Text Value
data Value
= Object ! Object
| Array ! Array
| String ! Text
| Number ! Number
| Bool ! Bool
| Null

Использованная нами функция object имеет следующий тип:

object :: [ ( Text , Value ) ] -> Value

Как вы уже догадались, она преобразует ассоциативный список в JSON-объект.

Вообще aeson — очень приятная в использовании библиотека:

ghci> :set -XOverloadedStrings
ghci> :m + Data.Aeson
ghci> import Data.ByteString.Lazy.Char8 as BSLC
ghci> BSLC.unpack $ encode $ object [(«aaa», Number 123)]
«{«aaa»»:123}»»
ghci> decode $ encode $ object [(«»aaa»»Number 123)] :: Maybe (Object)
Just fromList [(«»aaa»»Number 123)]
ghci> decode (BSLC.pack «»[12
admin

Share
Published by
admin

Recent Posts

Консоль удаленного рабочего стола(rdp console)

Клиент удаленного рабочего стола (rdp) предоставляет нам возможность войти на сервер терминалов через консоль. Что…

1 месяц ago

Настройка сети в VMware Workstation

В VMware Workstation есть несколько способов настройки сети гостевой машины: 1) Bridged networking 2) Network…

1 месяц ago

Логи брандмауэра Windows

Встроенный брандмауэр Windows может не только остановить нежелательный трафик на вашем пороге, но и может…

1 месяц ago

Правильный способ отключения IPv6

Вопреки распространенному мнению, отключить IPv6 в Windows Vista и Server 2008 это не просто снять…

1 месяц ago

Ключи реестра Windows, отвечающие за параметры экранной заставки

Параметры экранной заставки для текущего пользователя можно править из системного реестра, для чего: Запустите редактор…

1 месяц ago

Как управлять журналами событий из командной строки

В этой статье расскажу про возможность просмотра журналов событий из командной строки. Эти возможности можно…

1 месяц ago