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

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

Synopsis

Parsing and formatting

parseURLPathSource

Arguments

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

formatURLPathSource

Arguments

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

Parsing

type Parse a = Maybe aSource

Simple maybe alias.

parseConsSource

Arguments

:: Data a 
=> String

The constructor name.

-> [(String, String)]

The parameters.

-> Maybe a

The record value.

Parse a constructor from a string.

urlToAssocSource

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.

parseBool :: String -> Parse BoolSource

Parse a boolean (true/false).

Formatting

formatConsSource

Arguments

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

formatURLParamValueSource

Arguments

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

Misc

fieldToKeySource

Arguments

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