Monday, November 14, 2011
ANN: happstack-lite - a friendly introduction to Happstack
Happstack is a powerful Haskell web framework with a rich API that has
evolved over the last 7 years to meet the needs of real world web
development.
Unfortunately a rich and flexible API can also be daunting when all
you need is something simple. What many people don't realize is that
inside Happstack lives a very simple and easy to use web framework.
I am pleased to announce a new member of the Happstack family:
happstack-lite.
happstack-lite is minimal version of Happstack that is designed give
you everything you need to get started with web develop in a much
cleaner, easier package. It is an ideal starting point for novice Haskell programmers or developers who are new to the Happstack family.
We have done that by:
1. collecting the most essential types and functions into a single, well-documented module
2. giving all the functions simple type signatures. No crazy monad
transformers, far fewer type classes, etc.
3. creating a new, small tutorial (less than 2000 words) that shows
you how to use all the features of happstack-lite.
But, the best part is that happstack-lite is 100% compatible with regular Happstack. If you find you do need some of the extra features that Happstack offers, you can simply import the extra functions and use them. Migrating from happstack-lite to happstack is trivial -- mostly just changing `import Happstack.Lite` to `import Happstack.Server`. So, you are not locked into staying with happstack-lite if you decide you need more. And you can still use the many addon packages such as happstack-hsp or happstack-jmacro if you want.
happstack-lite is not crippled or underpowered. In fact, it offers features and performance on par with other Haskell frameworks while being as simple as possible. If you have ever looked at Happstack in the past and felt it was too complicated -- I would highly encourage to look again. Especially if the last time you looked was prior to Happstack 6.
Check out the tutorial here: happstack-lite.
We would love to hear your feedback and criticisms. Please see the related discussion at:
http://www.reddit.com/r/haskell.
Labels:
ANN,
happstack,
happstack-lite
Thursday, July 21, 2011
type-safe urls via web-routes, part 2: Boomerang
web-routes is a system for implementing type-safe web-routes in Haskell web applications. In part 1, we saw the basics of how to use web-routes.
In part 1, we used template haskell to automatically derive the mapping between the url string and the url type. This makes development very easy, but the automatically derived urls are not all that visually appealing.
In this part, we introduce a way to manually specify the mapping between the url type and the url string. This gives the developer 100% control over the mapping. Up to now, the problem with creating a manual mapping has been that you had to implement the specification twice. You had to write a show function to turn a url type into a url string, and a read function to turn a url string into a url type. These functions are basically inverses of each other, both following the same spec.
What we really want to do is write the spec once and automatically extract the printer and parser from the spec. That way we can be sure they are inverses of each other, and we do not have to repeat ourselves. And we do not have to repeat ourselves. Because that is annoying.
Fortunately, Sjoerd Visscher and Martijn van Steenbergen figured out exactly how to do that and published a proof of concept library know as Zwaluw. With permission, I have refactored their original library into two separate libraries: boomerang and web-routes-boomerang.
boomerang is a general purpose, standalone invertible parser library. web-routes-boomerang adds glue code around boomerang so that it can be used to with web-routes.
Using boomerang we can take a route like this one:
a specify a route map like this:
which defines a mapping like this:
The sitemap function looks like a ordinary parser. But, what makes it is exciting is that it also defines the pretty-printer at the same time.
For more in-depth details, see the relevant section of the Happstack Crash Course. If you just want to play with boomerang then start here.
In part 1, we used template haskell to automatically derive the mapping between the url string and the url type. This makes development very easy, but the automatically derived urls are not all that visually appealing.
In this part, we introduce a way to manually specify the mapping between the url type and the url string. This gives the developer 100% control over the mapping. Up to now, the problem with creating a manual mapping has been that you had to implement the specification twice. You had to write a show function to turn a url type into a url string, and a read function to turn a url string into a url type. These functions are basically inverses of each other, both following the same spec.
What we really want to do is write the spec once and automatically extract the printer and parser from the spec. That way we can be sure they are inverses of each other, and we do not have to repeat ourselves. And we do not have to repeat ourselves. Because that is annoying.
Fortunately, Sjoerd Visscher and Martijn van Steenbergen figured out exactly how to do that and published a proof of concept library know as Zwaluw. With permission, I have refactored their original library into two separate libraries: boomerang and web-routes-boomerang.
boomerang is a general purpose, standalone invertible parser library. web-routes-boomerang adds glue code around boomerang so that it can be used to with web-routes.
Using boomerang we can take a route like this one:
> data Sitemap > = Home > | Article ArticleId > | UserOverview > | UserDetail Int String > deriving (Eq, Ord, Read, Show, Data, Typeable) >
a specify a route map like this:
> sitemap :: Router Sitemap > sitemap = > ( rHome > <> rArticle . (lit "article" </> articleId) > <> lit "users" . users > ) > where > users = rUserOverview > <> rUserDetail </> int . lit "-" . anyString
which defines a mapping like this:
url | type | |
---|---|---|
/ | <=> | Home |
/article/int | <=> | Article int |
/users | <=> | UserOverview |
/users/int-string | <=> | UserDetail int string |
The sitemap function looks like a ordinary parser. But, what makes it is exciting is that it also defines the pretty-printer at the same time.
For more in-depth details, see the relevant section of the Happstack Crash Course. If you just want to play with boomerang then start here.
Monday, July 11, 2011
type-safe urls via web-routes, part 1
web-routes is a suite of libraries which provide "type-safe" web routing. Instead of working directly with url strings in your web application, you create types to represent the routes.
The web-routes library has been around for several years. The idea itself is fairly obvious to many Haskell programmers, and so the idea has been rediscovered many times.
web-routes is designed to be exceedingly flexible. It is not explicitly tied to any haskell web framework, templating system, etc. It forms the basis of type-safe urls in yesod. There is also support for Happstack and HSP.
web-routes does not impose any particular method of mapping the url types to strings. We provide a variety of ways to defining mappings via addons including quasi-quotation, template haskell, generics, parsec, and more. If none of these systems suit your fancy, you can easily provide your own system. You basically need to provide two functions:
If you have an idea for how to map urls to types, I would encourage you to consider basing it on web-routes. A significant amount of effort has gone into handling issues like unicode and url escaping (among other things). If you use web-routes you do not need to know *any* of those rules. web-routes takes care of all that nastiness for you. If you find that web-routes is not suitable for your needs, I would love to hear why and see if we can not fix it.
The biggest issue with web-routes has been the lack of good documentation. So, I am pleased to announce that the first in a series of tutorials on web-routes is now online at: http://happstack.com/docs/crashcourse/WebRoutes.html.
Comments, questions, and corrections appreciated!
The web-routes library has been around for several years. The idea itself is fairly obvious to many Haskell programmers, and so the idea has been rediscovered many times.
web-routes is designed to be exceedingly flexible. It is not explicitly tied to any haskell web framework, templating system, etc. It forms the basis of type-safe urls in yesod. There is also support for Happstack and HSP.
web-routes does not impose any particular method of mapping the url types to strings. We provide a variety of ways to defining mappings via addons including quasi-quotation, template haskell, generics, parsec, and more. If none of these systems suit your fancy, you can easily provide your own system. You basically need to provide two functions:
urlToString :: url -> [(String, String)] -> [String]
stringToUrl :: [String] -> Either String url
If you have an idea for how to map urls to types, I would encourage you to consider basing it on web-routes. A significant amount of effort has gone into handling issues like unicode and url escaping (among other things). If you use web-routes you do not need to know *any* of those rules. web-routes takes care of all that nastiness for you. If you find that web-routes is not suitable for your needs, I would love to hear why and see if we can not fix it.
The biggest issue with web-routes has been the lack of good documentation. So, I am pleased to announce that the first in a series of tutorials on web-routes is now online at: http://happstack.com/docs/crashcourse/WebRoutes.html.
Comments, questions, and corrections appreciated!
Labels:
routing,
type-safe,
web-routes
Monday, May 23, 2011
Happstack + JMacro + HSX
Happstack (a Haskell web framework) has long had support for using HSX so that you can use XML syntax in your Haskell page templates. Happstack now has support for using JMacro to add javascript to your templates.
JMacro was written by Gershom Bazerman, and was first released in July of 2009. Our contribution is the creation of two glue libraries:
The use of Happstack+HSX+JMacro has been documented in detail in this section of the Happstack Crash Course.
Here is a little example of what Happstack+HSX+JMacro looks like:
As you can see, the syntax used by JMacro is almost identical to JavaScript. So, you do not have to learn some special DSL to use it. In fact, JMacro can work with most JavaScript you find in the wild. Using JMacro has a number of advantages over just using plain-old javascript:
The last point means that instead of trying to concat strings to call JavaScript functions with Haskell values like this:
You can write:
The first version has a major bug -- it does not properly escape the
You are not limited to just splicing strings and other primitive types into the JavaScript code. By creating an instance of
While JMacro can easily be used for simple templating, it is actually a very powerful tool for generating JavaScript. It is essentially Template Haskell for JavaScript. It parses the JavaScript into an abstract syntax tree, and supports quasiquotation and antiquotation.
To learn more about using JMacro with Happstack and HSX, start reading here.
And a big thanks for Gershom Bazerman for creating JMacro. It's not part of Happstack or HSX, so you should have no problems using it with other web frameworks or templating libraries.
JMacro was written by Gershom Bazerman, and was first released in July of 2009. Our contribution is the creation of two glue libraries:
- hsx-jmacro
- a thin wrapper which makes it easy to embed JMacro into HSX (independent of Happstack).
- happstack-jmacro
- another thin wrapper that makes it easy to generate and serve JMacro .js scripts using Happstack
The use of Happstack+HSX+JMacro has been documented in detail in this section of the Happstack Crash Course.
Here is a little example of what Happstack+HSX+JMacro looks like:
> helloJMacro :: JMacroPart Response > helloJMacro = > toResponse <$> defaultTemplate "Hello JMacro" () > <div> > <% [$jmacro| > var helloNode = document.createElement('h1'); > helloNode.appendChild(document.createTextNode("Hello, JMacro!")); > document.body.appendChild(helloNode); > |] %> > </div> >
As you can see, the syntax used by JMacro is almost identical to JavaScript. So, you do not have to learn some special DSL to use it. In fact, JMacro can work with most JavaScript you find in the wild. Using JMacro has a number of advantages over just using plain-old javascript:
- syntax checking ensures that your JavaScript is syntactically valid at compile time. That eliminates many common JavaScript errors and reduces development time.
- hygienic names and scoping automatically and transparently ensure that blocks of JavaScript code do not accidentally create variables and functions with conflicting names.
- Antiquotation, marshalling, and shared scope make it easy to splice Haskell values into the JavaScript code. It also makes it easy to programmatically generate JavaScript code.
The last point means that instead of trying to concat strings to call JavaScript functions with Haskell values like this:
hello str = <button onclick=("alert(" ++ str ++ ");")>click me</button>
You can write:
hello str = <button onclick=[$jmacro| alert(`(str)`); |]>click me</button>
The first version has a major bug -- it does not properly escape the
str
which can lead to javascript injection attacks. The JMacro version, on the other hand, automatically escapes the string.You are not limited to just splicing strings and other primitive types into the JavaScript code. By creating an instance of
ToJExpr
you can easily pass any Haskell value to JavaScript.While JMacro can easily be used for simple templating, it is actually a very powerful tool for generating JavaScript. It is essentially Template Haskell for JavaScript. It parses the JavaScript into an abstract syntax tree, and supports quasiquotation and antiquotation.
To learn more about using JMacro with Happstack and HSX, start reading here.
And a big thanks for Gershom Bazerman for creating JMacro. It's not part of Happstack or HSX, so you should have no problems using it with other web frameworks or templating libraries.
Labels:
happstack,
hsx,
jmacro,
templating
Monday, May 2, 2011
MACID Haskell persistent data store overhauled
Over the past few weeks Lemmih has been working on a major overhaul of MACID. MACID is a persistent data store explicitly designed for use with Haskell. It can store arbitrary Haskell data structures and queries are written in straight-forward Haskell (no funky DSLs). It is thread-safe, and supports the classic ACID properties. Unplug your machine with out losing your data.
The homepage for the new MACID library can be found here.
There are two new libraries acid-state and safecopy, which will replace happstack-data and happstack-state in Happstack 7.
safecopy provides versioned binary serialization of datatypes with version migration. It adds this functionality on top of the cereal library.
acid-state provides ACID transactions on top of safecopy.
The new MACID is like the old MACID, but better. The fundamental concepts are the same, but it is a lot cleaner, more robust and less magical.
The rewrite of MACID addresses many long standing wish-list items, including:
acid-state and safecopy are now free standing libraries, with no references or dependencies on anything Happstack. They have their own maintainer, homepage, source repository, etc. So, now you can used MACID, even if you don't use Happstack. (This has actually been true for a while, but now it is a lot more obvious).
If all you want is versioned binary serialization and migration, then you can use the safecopy library on its own.
In happstack-state, query and update accessed the state via a global IORef. This meant that you could only have one instance of MACID per application. It also weakened type-checking resulting runtime errors that should have been avoidable.
It also meant that you could only have one ACID store per application.
Now update and query take an explicit handle.
happstack-state has a Component class, which is mostly worthless. It gives the promise of power, but doesn't really deliver anything. It is just extra boilerplate for the most part. This class is gone entirely in acid-state.
In happstack-data, creating a Serialization instance for a type required you to call
In happstack-data there were three type classes,
happstack-state has a number of corner cases that it does not handle gracefully. For example, bad things happen if update events call fail or error. acid-state handles these correctly and includes a test suite specifically for testing these types of failures.
Additionally, acid-state is a lot better at flushing data to disk.
Initial performance testing shows that acid-state is fast. A simple data store that holds an integer which is incremented by an update event was able to achieve 13,300 updates per second.
There is still a bunch of work to come.
acid-state currently does not support Windows. This is because the code to safely flush data to disk requires the posix library. Windows support can be added via some #ifdefs. If you are familiar with Windows and file IO and want to help, your contribution will be greatly appreciated.
Migrating data from happstack-state to acid-state is certainly feasible, but the process is not yet documented. But it will be.
There are also major improvements to IxSet planned.
And, of course, replication and sharding. Fortunately, it will be easier to implement these on top of the new acid-state code base.
acid-state is usable today! You can install it from hackage. There are code examples here and here. If you are starting a new MACID based project, you are encouraged to consider acid-state.
To use happstack-ixset you will currently need to add this extra instance to your code:
Once IxSet is factored out of happstack into a separate library that instance will be provided automatically.
It is safe to mix happstack-state and acid-state in the same application if you want to use acid-state in an existing application.
More updates to come as things develop!
The homepage for the new MACID library can be found here.
There are two new libraries acid-state and safecopy, which will replace happstack-data and happstack-state in Happstack 7.
safecopy provides versioned binary serialization of datatypes with version migration. It adds this functionality on top of the cereal library.
acid-state provides ACID transactions on top of safecopy.
What's New
The new MACID is like the old MACID, but better. The fundamental concepts are the same, but it is a lot cleaner, more robust and less magical.
The rewrite of MACID addresses many long standing wish-list items, including:
MACID now a separate project
acid-state and safecopy are now free standing libraries, with no references or dependencies on anything Happstack. They have their own maintainer, homepage, source repository, etc. So, now you can used MACID, even if you don't use Happstack. (This has actually been true for a while, but now it is a lot more obvious).
If all you want is versioned binary serialization and migration, then you can use the safecopy library on its own.
update / query take an explicit state handle now
In happstack-state, query and update accessed the state via a global IORef. This meant that you could only have one instance of MACID per application. It also weakened type-checking resulting runtime errors that should have been avoidable.
It also meant that you could only have one ACID store per application.
Now update and query take an explicit handle.
No more Component class
happstack-state has a Component class, which is mostly worthless. It gives the promise of power, but doesn't really deliver anything. It is just extra boilerplate for the most part. This class is gone entirely in acid-state.
Less boilerplate for serialization instances
In happstack-data, creating a Serialization instance for a type required you to call
$(deriveSerialize ''Foo)
and you have to create an instance Version Foo
. With safecopy, you only need one line, '$(deriveSafeCopy 0 'base ''Foo)'In happstack-data there were three type classes,
Serialize
, Version
, and Migrate
. This has been simplified down to just two in safecopy: SafeCopy
and Migrate
.Better Safety
happstack-state has a number of corner cases that it does not handle gracefully. For example, bad things happen if update events call fail or error. acid-state handles these correctly and includes a test suite specifically for testing these types of failures.
Additionally, acid-state is a lot better at flushing data to disk.
Performance
Initial performance testing shows that acid-state is fast. A simple data store that holds an integer which is incremented by an update event was able to achieve 13,300 updates per second.
Still Coming
There is still a bunch of work to come.
acid-state currently does not support Windows. This is because the code to safely flush data to disk requires the posix library. Windows support can be added via some #ifdefs. If you are familiar with Windows and file IO and want to help, your contribution will be greatly appreciated.
Migrating data from happstack-state to acid-state is certainly feasible, but the process is not yet documented. But it will be.
There are also major improvements to IxSet planned.
And, of course, replication and sharding. Fortunately, it will be easier to implement these on top of the new acid-state code base.
Get Started Today
acid-state is usable today! You can install it from hackage. There are code examples here and here. If you are starting a new MACID based project, you are encouraged to consider acid-state.
To use happstack-ixset you will currently need to add this extra instance to your code:
import Data.SafeCopy import Happstack.Data.IxSet (IxSet) import qualified Happstack.Data.IxSet as IxSet instance (SafeCopy a, Ord a, Typeable a, IxSet.Indexable a) => SafeCopy (IxSet a) where putCopy ixSet = contain $ safePut (IxSet.toList ixSet) getCopy = contain $ IxSet.fromList <$> safeGet
Once IxSet is factored out of happstack into a separate library that instance will be provided automatically.
It is safe to mix happstack-state and acid-state in the same application if you want to use acid-state in an existing application.
More updates to come as things develop!
Labels:
acid-state,
database,
MACID,
persistence,
safecopy
Subscribe to:
Posts (Atom)