introduction to yesod
TRANSCRIPT
Introduction to Yesod
@bobjlong - Kats Conf 2015, Dublin
Brief overview + concepts
Composition
Builds and deployments
About me
twitter.com/bobjlong
github.com/bobjflong
Web development
Professional history of Rails
Late-night Haskell enthusiast
Haskell web dev
Rich types
Performance
Joy of discovery
Libraries
Error class elimination
Everyday problems
Wiring
Encoding issues
Safety (XSS)
Performance, concurrency
What is Yesod?
“A developer should be able to continue to productively write code as their application
grows and more team members join.”
“The key to achieving this is applying Haskell's type-safety to an otherwise
traditional MVC REST web framework.”
http://www.yesodweb.com/page/about
Introducting Yesod ✨Concepts✨
Routing & Handlers
DSLs
Composability
“Persistent”
- a safe and productive query interface
Familiarity
- conventions + scaffolding
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeFamilies #-}
import Yesod
data HelloWorld = HelloWorld
mkYesod "HelloWorld" [parseRoutes| / HomeR GET |]
instance Yesod HelloWorld
getHomeR :: Handler Html getHomeR = defaultLayout [whamlet|Hello World!|]
main :: IO () main = warp 3000 HelloWorld
routing
handler
starting a web server
Composition
Case study: yesod-transloadit
Transloadit
a webservice for handling file uploads, transformations, transcoding etc.
jQuery dependency
transloadit.js
server-side scripting to compute HMAC
client-side scripting to “attach” transloadit
server-side scripting to handle response from Transloadit
where are client side assets loaded?
getHomeR :: Handler Html getHomeR = defaultLayout $ do let now = UTCTime (ModifiedJulianDay 50000) (secondsToDiffTime 10)
ident <- newIdent
let expiry = addUTCTime 3600 now key = Key "my_key" template = Template "my_template" secret = Secret "my_secret" params = mkParams expiry key template ident secret
sig <- either (const $ error "nooo") transloadIt params
t <- tokenText
[whamlet| <form id="#{ident}" action=@{HomeR} method="POST"> <input type="hidden" name="_token" value="#{t}"> <input type="hidden" name="signature" value="#{sig}"> <input type="file" name="my_file"> <input type="submit" value="Upload"> |] return ()
postHomeR :: Handler Html postHomeR = defaultLayout $ do results <- handleTransloadit
case nthStepResult 0 "cropped_thumb" results of Just s -> [whamlet| <img src="#{s ^. sslUrl}"/> |] _ -> [whamlet| No results :( |]
return ()
How?
github.com/bobjflong/yesod-transloadit
Yesod has a generic WidgetT type that works for all web-apps
Typeclasses are used to enforce dependencies
transloadIt :: (YesodJquery m, YesodTransloadit m) => TransloaditParams -> WidgetT m IO Signature
data Test = Test
instance Yesod Test instance YesodJquery Test instance YesodTransloadit Test
— or
instance YesodTransloadit Test where transloaditRoot _ = “https://my_cdn.com/“
Persistent
share [mkPersist sqlSettings, mkMigrate “migrateAll”] [persistLowerCase| Person name String age Int Maybe deriving Show BlogPost title String authorId PersonId deriving Show |]
johnId <- insert $ Person "John Doe" $ Just 35
oneJohnPost <- selectList [BlogPostAuthorId ==. johnId] [LimitTo 1]
esqueleto
“esqueleto is a bare bones, type-safe EDSL for SQL queries that works with unmodified persistent SQL backends”
https://hackage.haskell.org/package/esqueleto
E.selectSource $ E.from $ \(blog `E.InnerJoin` author) -> do E.on $ blog ^. BlogAuthor E.==. author ^. AuthorId return ( blog ^. BlogId , blog ^. BlogTitle , author ^. AuthorName )
Building & deploying
Cabal
Stack
Nix
Quick intro to Nix
Reproducible, stable builds
Binaries
Complete dependency graphs
Immutable Infrastructure
1. Pre-bake an AMI with a Nix environment
2. Build a new AMI per app version with Nix
3. Associate new instances with the ASG
http://bobjflong.co/posts/2015-08-22-yesod.html
Questions?
@bobjlong
https://github.com/bitemyapp/learnhaskell http://www.yesodweb.com/book