url-generic-0.1: Parse/format generic key/value URLs from record data types.




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

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

The supported types for URL parameters are:

  • Standard Integer type.
  • Standard Bool type.
  • Any type with nullary constructors (such as Layout above.).
  • Maybe a where a 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 Strings. 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.


Parsing and formatting



:: Data a 
=> String

The URL path.

-> Maybe a

The record.

Parse a URL path, e.g. /foo/id/1, into its corresponding data type, e.g. Foo { fooId = 1 }.



:: Data a 
=> a

The record.

-> String

The URL path.

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)


type Parse a = Maybe aSource

Simple maybe alias.



:: Data a 
=> String

The constructor name.

-> [(String, String)]

The parameters.

-> Maybe a

The record value.

Parse a constructor from a string.



:: 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.

parseBool :: String -> Parse BoolSource

Parse a boolean (true/false).




:: Data a 
=> a

The record value to format, e.g. Foo { fooId = 1 }

-> String

The corresponding URL, e.g. /foo/id/1

Format a constructor value to a URL.



:: Data a 
=> a

A URL parameter value.

-> String

A URL-friendly version.

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.




:: Show a 
=> a

The Haskell constructor e.g. Foo.

-> String

The field name e.g. fooBarMu.

-> String

The slug e.g. bar-mu.

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.