HORIZON HASKELLDocslts/ghc-9.10.xc74966e2026-09-27Search names, modules, packages, or :: a typeCtrl K

GHC 9.10.3 · lts/ghc-9.10.x · c74966e · 2026-09-27

Modulehttp-api-data-0.6.1Haskell2010

Web.Internal.FormUrlEncoded

  • 3 types
  • 6 classes
  • 22 values
  • Packagehttp-api-data-0.6.1
  • Exports32
  • LanguageHaskell2010
  • LicenceBSD-3-Clause
  • SourceFormUrlEncoded.hs
Example5 expressions
:set -XDeriveGeneric -XOverloadedLists -XOverloadedStrings -XFlexibleContexts -XScopedTypeVariables -XTypeFamiliesimport GHC.Generics (Generic)import Data.Char (toLower)import Data.Text (Text)import Data.Word (Word8)
Example3 expressions
data Person = Person { name :: String, age :: Int } deriving (Show, Generic)instance ToForm Personinstance FromForm Person
Example3 expressions
data Post = Post { title :: String, subtitle :: Maybe String, comments :: [String]} deriving (Generic, Show)instance ToForm Postinstance FromForm Post
Example4 expressions
data Project = Project { projectName :: String, projectSize :: Int } deriving (Generic, Show)let myOptions = FormOptions { fieldLabelModifier = map toLower . drop (length ("project" :: String)) }instance ToForm Project where toForm = genericToForm myOptionsinstance FromForm Project where fromForm = genericFromForm myOptions
classclass ToFormKey k where
#

Typeclass for types that can be used as keys in a Form-like container (like Map).

Methods

Instances42ToFormKey, …
classclass FromFormKey k where
#

Typeclass for types that can be parsed from keys of a Form. This is the reverse of ToFormKey.

Methods

Instances42FromFormKey, …
newtypenewtype Form
#

The contents of a form, not yet URL-encoded.

Form can be URL-encoded with urlEncodeForm and URL-decoded with urlDecodeForm.

Constructors

Instances11IsList, Eq, Read, Show, Generic, Semigroup, …
classclass ToForm a where
#

Convert a value into Form.

An example type and instance:

{-# LANGUAGE OverloadedLists #-}

data Person = Person
  { name :: String
  , age  :: Int }

instance ToForm Person where
  toForm person =
    [ ("name", toQueryParam (name person))
    , ("age", toQueryParam (age person)) ]

Instead of manually writing ToForm instances you can use a default generic implementation of toForm.

To do that, simply add deriving Generic clause to your datatype and declare a ToForm instance for your datatype without giving definition for toForm.

For instance, the previous example can be simplified into this:

data Person = Person
  { name :: String
  , age  :: Int
  } deriving (Generic)

instance ToForm Person

The default implementation of toForm is genericToForm.

Methods

Instances5ToForm
valuefromEntriesByKey :: (ToFormKey k, ToHttpApiData v) => [(k, [v])] -> Form
#

Convert a list of entries groupped by key into a Form.

Example1 expression
fromEntriesByKey [("name",["Nick"]),("color",["red","blue"])]fromList [("color","red"),("color","blue"),("name","Nick")]
familytype family NotSupported (cls :: k1) (a :: k2) (reason :: Symbol) :: Constraint where
#

Equations

valuegenericToForm :: (Generic a, GToForm a (Rep a)) => FormOptions -> a -> Form
#

A Generic-based implementation of toForm. This is used as a default implementation in ToForm.

Note that this only works for records (i.e. product data types with named fields):

data Person = Person
  { name :: String
  , age  :: Int
  } deriving (Generic)

In this implementation each field's value gets encoded using toQueryParam. Two field types are exceptions:

  • for values of type Maybe a an entry is added to the Form only when it is Just x and the encoded value is toQueryParam x; Nothing values are omitted from the Form;

  • for values of type [a] (except [Char]) an entry is added for every item in the list; if the list is empty no entries are added to the Form;

Here's an example:

data Post = Post
  { title    :: String
  , subtitle :: Maybe String
  , comments :: [String]
  } deriving (Generic, Show)

instance ToForm Post
Example1 expression
urlEncodeAsFormStable Post { title = "Test", subtitle = Nothing, comments = ["Nice post!", "+1"] }"comments=Nice%20post%21&comments=%2B1&title=Test"
classclass GToForm (t :: k) (f :: Type -> Type) where
#

Methods

Instances8GToForm, …
classclass FromForm a where
#

Parse Form into a value.

An example type and instance:

data Person = Person
  { name :: String
  , age  :: Int }

instance FromForm Person where
  fromForm f = Person
    <$> parseUnique "name" f
    <*> parseUnique "age"  f

Instead of manually writing FromForm instances you can use a default generic implementation of fromForm.

To do that, simply add deriving Generic clause to your datatype and declare a FromForm instance for your datatype without giving definition for fromForm.

For instance, the previous example can be simplified into this:

data Person = Person
  { name :: String
  , age  :: Int
  } deriving (Generic)

instance FromForm Person

The default implementation of fromForm is genericFromForm. It only works for records and it will use parseQueryParam for each field's value.

Methods

Instances5FromForm

A Generic-based implementation of fromForm. This is used as a default implementation in FromForm.

Note that this only works for records (i.e. product data types with named fields):

data Person = Person
  { name :: String
  , age  :: Int
  } deriving (Generic)

In this implementation each field's value gets decoded using parseQueryParam. Two field types are exceptions:

  • for values of type Maybe a an entry is parsed if present in the Form and the is decoded with parseQueryParam; if no entry is present result is Nothing;

  • for values of type [a] (except [Char]) all entries are parsed to produce a list of parsed values;

Here's an example:

data Post = Post
  { title    :: String
  , subtitle :: Maybe String
  , comments :: [String]
  } deriving (Generic, Show)

instance FromForm Post
Example1 expression
urlDecodeAsForm "comments=Nice%20post%21&comments=%2B1&title=Test" :: Either Text PostRight (Post {title = "Test", subtitle = Nothing, comments = ["Nice post!","+1"]})
classclass GFromForm (t :: k) (f :: Type -> Type) where
#

Methods

Instances8GFromForm, …

Encode a Form to an application/x-www-form-urlencoded ByteString.

For an unstable (but faster) encoding see urlEncodeForm.

Key-value pairs get encoded to key=value and separated by &:

Example1 expression
urlEncodeFormStable [("name", "Julian"), ("lastname", "Arni")]"lastname=Arni&name=Julian"

Keys with empty values get encoded to just key (without the = sign):

Example1 expression
urlEncodeFormStable [("is_test", "")]"is_test"

Empty keys are allowed too:

Example1 expression
urlEncodeFormStable [("", "foobar")]"=foobar"

However, if both key and value are empty, the key-value pair is ignored. (This prevents urlDecodeForm . urlEncodeFormStable from being a true isomorphism).

Example1 expression
urlEncodeFormStable [("", "")]""

Everything is escaped with escapeURIString isUnreserved:

Example1 expression
urlEncodeFormStable [("fullname", "Andres Löh")]"fullname=Andres%20L%C3%B6h"

Decode an application/x-www-form-urlencoded ByteString to a Form.

Key-value pairs get decoded normally:

Example1 expression
urlDecodeForm "name=Greg&lastname=Weber"Right (fromList [("lastname","Weber"),("name","Greg")])

Keys with no values get decoded to pairs with empty values.

Example1 expression
urlDecodeForm "is_test"Right (fromList [("is_test","")])

Empty keys are allowed:

Example1 expression
urlDecodeForm "=foobar"Right (fromList [("","foobar")])

The empty string gets decoded into an empty Form:

Example1 expression
urlDecodeForm ""Right (fromList [])

Everything is un-escaped with unEscapeString:

Example1 expression
urlDecodeForm "fullname=Andres%20L%C3%B6h"Right (fromList [("fullname","Andres L\246h")])

Improperly formed strings result in an error:

Example1 expression
urlDecodeForm "this=has=too=many=equals"Left "not a valid pair: this=has=too=many=equals"
valuelookupAll :: Text -> Form -> [Text]
#

Find all values corresponding to a given key in a Form.

Example3 expressions
lookupAll "name" [][]lookupAll "name" [("name", "Oleg")]["Oleg"]lookupAll "name" [("name", "Oleg"), ("name", "David")]["Oleg","David"]
valuelookupMaybe :: Text -> Form -> Either Text (Maybe Text)
#

Lookup an optional value for a key. Fail if there is more than one value.

Example3 expressions
lookupMaybe "name" []Right NothinglookupMaybe "name" [("name", "Oleg")]Right (Just "Oleg")lookupMaybe "name" [("name", "Oleg"), ("name", "David")]Left "Duplicate key \"name\""
valuelookupUnique :: Text -> Form -> Either Text Text
#

Lookup a unique value for a key. Fail if there is zero or more than one value.

Example3 expressions
lookupUnique "name" []Left "Could not find key \"name\""lookupUnique "name" [("name", "Oleg")]Right "Oleg"lookupUnique "name" [("name", "Oleg"), ("name", "David")]Left "Duplicate key \"name\""
valueparseAll :: FromHttpApiData v => Text -> Form -> Either Text [v]
#

Lookup all values for a given key in a Form and parse them with parseQueryParams.

Example4 expressions
parseAll "age" [] :: Either Text [Word8]Right []parseAll "age" [("age", "8"), ("age", "seven")] :: Either Text [Word8]Left "could not parse: `seven' (input does not start with a digit)"parseAll "age" [("age", "8"), ("age", "777")] :: Either Text [Word8]Left "out of bounds: `777' (should be between 0 and 255)"parseAll "age" [("age", "12"), ("age", "25")] :: Either Text [Word8]Right [12,25]
valueparseMaybe :: FromHttpApiData v => Text -> Form -> Either Text (Maybe v)
#

Lookup an optional value for a given key and parse it with parseQueryParam. Fail if there is more than one value for the key.

Example5 expressions
parseMaybe "age" [] :: Either Text (Maybe Word8)Right NothingparseMaybe "age" [("age", "12"), ("age", "25")] :: Either Text (Maybe Word8)Left "Duplicate key \"age\""parseMaybe "age" [("age", "seven")] :: Either Text (Maybe Word8)Left "could not parse: `seven' (input does not start with a digit)"parseMaybe "age" [("age", "777")] :: Either Text (Maybe Word8)Left "out of bounds: `777' (should be between 0 and 255)"parseMaybe "age" [("age", "7")] :: Either Text (Maybe Word8)Right (Just 7)
valueparseUnique :: FromHttpApiData v => Text -> Form -> Either Text v
#

Lookup a unique value for a given key and parse it with parseQueryParam. Fail if there is zero or more than one value for the key.

Example5 expressions
parseUnique "age" [] :: Either Text Word8Left "Could not find key \"age\""parseUnique "age" [("age", "12"), ("age", "25")] :: Either Text Word8Left "Duplicate key \"age\""parseUnique "age" [("age", "seven")] :: Either Text Word8Left "could not parse: `seven' (input does not start with a digit)"parseUnique "age" [("age", "777")] :: Either Text Word8Left "out of bounds: `777' (should be between 0 and 255)"parseUnique "age" [("age", "7")] :: Either Text Word8Right 7
datadata FormOptions
#

Generic-based deriving options for ToForm and FromForm.

A common use case for non-default FormOptions is to strip a prefix off of field labels:

data Project = Project
  { projectName :: String
  , projectSize :: Int
  } deriving (Generic, Show)

myOptions :: FormOptions
myOptions = FormOptions
 { fieldLabelModifier = map toLower . drop (length "project") }

instance ToForm Project where
  toForm = genericToForm myOptions

instance FromForm Project where
  fromForm = genericFromForm myOptions
Example2 expressions
urlEncodeAsFormStable Project { projectName = "http-api-data", projectSize = 172 }"name=http-api-data&size=172"urlDecodeAsForm "name=http-api-data&size=172" :: Either Text ProjectRight (Project {projectName = "http-api-data", projectSize = 172})

Constructors

valuesortOn :: Ord b => (a -> b) -> [a] -> [a]
#