Web.URL.Generic
Contents
Description
The purpose of this package is to associate web pages each with a data type that contains all the necessary parameters for that page, by automatically deriving that representation from the data types themselves. It is an experimental package to test the idea.
The data type constructors must be nullary or record, and there should only be one constructor (later this might be revised). The fields of the constructor MUST each be prefixed with the name of the constructor, as per the common idiom when dealing with Haskell data types. This also ensures that no data-type-generated URL can be in conflict with another, code-wise or representation-wise.
For example, consider a page displays some conference/event. It ought to be defined thiswise:
data Event = Event { eventId :: Maybe Integer -- ^ The event id. , eventScope :: Bool -- ^ Show the scope? , eventLayout :: Layout -- ^ Layout for the page. } deriving (Data,Typeable,Show)
And an Enum type for layout:
data Layout = Wide | Thin | Collapsed deriving (Typeable,Data,Show,Enum)
(Show
is not required, but is included for inspection purposes.)
Now I can format that as a URL:
> formatURLPath $ Event (Just 0) False Wide "/event/id/0/layout/wide"
And parse that URL back in:
> parseURLPath "/event/id/0/layout/wide" :: Maybe Event Just (Event {eventId = Just 0, eventScope = False, eventLayout = Wide})
Nullary data types also work:
data Home = Home deriving (Data,Typeable,Show) > parseURLPath "/home" :: Maybe Home Just Home > formatURLPath Home "/home" >
The supported types for URL parameters are:
- Standard
Integer
type. - Standard
Bool
type. - Any type with nullary constructors (such as
Layout
above.). -
Maybe a
wherea
is one of the above. Maybe is useful for optionally omitting parameters from URLs.
Any other types cannot (should not (?)) be serialized at the URL-level.
There is the possibility to read/write String
, but it does make
much sense to put arbitrary strings in URLs, so it does no special
encoding/decoding for String
s. There is, however, the use case for
encoding slugs, such as blog titles, e.g. /posts/name/my-blog-title
, and that
is why support is included. You must ensure that these are properly
normalized yourself.
- parseURLPath :: Data a => String -> Maybe a
- formatURLPath :: Data a => a -> String
- type Parse a = Maybe a
- parseCons :: Data a => String -> [(String, String)] -> Maybe a
- urlToAssoc :: String -> [(String, String)]
- fromURLString :: Data a => String -> Maybe a
- parseData :: Data a => String -> Parse a
- parseInteger :: String -> Parse Integer
- parseBool :: String -> Parse Bool
- formatCons :: Data a => a -> String
- formatURLParamValue :: Data a => a -> String
- showData :: Data a => a -> String
- fieldToKey :: Show a => a -> String -> String
- upperToDashes :: [Char] -> [Char]
- dashesToUpper :: [Char] -> [Char]
Parsing and formatting
Parse a URL path, e.g. /foo/id/1
, into its corresponding data
type, e.g. Foo { fooId = 1 }
.
Format a record value, e.g. Foo { fooId = 1 }
, into its
corresponding URL path, e.g. /foo/id/1
.
Internal API (i.e. not stable; subject to change; for educational purposes)
Parsing
Arguments
:: Data a | |
=> String | The constructor name. |
-> [(String, String)] | The parameters. |
-> Maybe a | The record value. |
Parse a constructor from a string.
Arguments
:: String | A string containing /foo/1/bar/2 key/values. |
-> [(String, String)] | An association list. |
URL string to association list.
fromURLString :: Data a => String -> Maybe aSource
Parse a URL string into a simple value (integer/bool/string).
parseData :: Data a => String -> Parse aSource
Parse any constructor. It really only works well for nullary constructors like Enum values, but that in itself is very useful.
parseInteger :: String -> Parse IntegerSource
Parse an integer.
Formatting
Arguments
:: Data a | |
=> a | The record value to format, e.g. |
-> String | The corresponding URL, e.g. |
Format a constructor value to a URL.
Format a constructor's field value to a URL parameter.
showData :: Data a => a -> StringSource
Show any Haskell (Data instance) constructor e.g. FooBar
to
foo-bar
. This is only reliable for nullary constructors like Enums
and such. But that by itself is very useful, so it's worth including.
Misc
Arguments
:: Show a | |
=> a | The Haskell constructor e.g. |
-> String | The field name e.g. |
-> String | The slug e.g. |
Normalize a record field to a slug-ish name e.g. fooBarMu
=> bar-mu
.
upperToDashes :: [Char] -> [Char]Source
Convert uppercase CamelCase to slug-ish camel-case
.
dashesToUpper :: [Char] -> [Char]Source
Convert slug-ish camel-case
to uppercase CamelCase
.