git.iko.soy/typeable/http-api-data
on master help sign in
Add more docs explaining special roles of Maybe and lists
f59b5c9Nickolay Kudasov
src/Web/Internal/FormUrlEncoded.hs+51−1
@@ -75,6 +75,10 @@ import Web.Internal.HttpApiData
75-- >>> instance ToForm Person
75-- >>> instance ToForm Person
76-- >>> instance FromForm Person
76-- >>> instance FromForm Person
77--
77--
78+-- >>> data Post = Post { title :: String, subtitle :: Maybe String, comments :: [String]} deriving (Generic, Show)
79+-- >>> instance ToForm Post
80+-- >>> instance FromForm Post
81+--
78-- >>> data Project = Project { projectName :: String, projectSize :: Int } deriving (Generic, Show)
82-- >>> data Project = Project { projectName :: String, projectSize :: Int } deriving (Generic, Show)
79-- >>> let myOptions = FormOptions { fieldLabelModifier = map toLower . drop (length ("project" :: String)) }
83-- >>> let myOptions = FormOptions { fieldLabelModifier = map toLower . drop (length ("project" :: String)) }
80-- >>> instance ToForm Project where toForm = genericToForm myOptions
84-- >>> instance ToForm Project where toForm = genericToForm myOptions
@@ -225,7 +229,6 @@ instance IsList Form where
225-- @
229-- @
226--
230--
227-- The default implementation of 'toForm' is 'genericToForm'.
231-- The default implementation of 'toForm' is 'genericToForm'.
228−-- It only works for records and it will use 'toQueryParam' for each field's value.
229class ToForm a where
232class ToForm a where
230 -- | Convert a value into 'Form'.
233 -- | Convert a value into 'Form'.
231 toForm :: a -> Form
234 toForm :: a -> Form
@@ -278,6 +281,30 @@ type family NotSupported (cls :: k1) (a :: k2) (reason :: Symbol) :: Constraint
278-- , age :: Int
281-- , age :: Int
279-- } deriving ('Generic')
282-- } deriving ('Generic')
280-- @
283-- @
284+--
285+-- In this implementation each field's value gets encoded using `toQueryParam`.
286+-- Two field types are exceptions:
287+--
288+-- - for values of type @'Maybe' a@ an entry is added to the 'Form' only when it is @'Just' x@
289+-- and the encoded value is @'toQueryParam' x@; 'Nothing' values are omitted from the 'Form';
290+--
291+-- - for values of type @[a]@ (except @['Char']@) an entry is added for every item in the list;
292+-- if the list is empty no entries are added to the 'Form';
293+--
294+-- Here's an example:
295+--
296+-- @
297+-- data Post = Post
298+-- { title :: String
299+-- , subtitle :: Maybe String
300+-- , comments :: [String]
301+-- } deriving ('Generic', 'Show')
302+--
303+-- instance 'ToForm' Post
304+-- @
305+--
306+-- >>> urlEncodeAsForm Post { title = "Test", subtitle = Nothing, comments = ["Nice post!", "+1"] }
307+-- "comments=Nice%20post%21&comments=%2B1&title=Test"
281genericToForm :: forall a. (Generic a, GToForm a (Rep a)) => FormOptions -> a -> Form
308genericToForm :: forall a. (Generic a, GToForm a (Rep a)) => FormOptions -> a -> Form
282genericToForm opts = gToForm (Proxy :: Proxy a) opts . from
309genericToForm opts = gToForm (Proxy :: Proxy a) opts . from
283
310
@@ -393,6 +420,29 @@ toEntriesByKey = traverse parseGroup . HashMap.toList . unForm
393-- , age :: Int
420-- , age :: Int
394-- } deriving ('Generic')
421-- } deriving ('Generic')
395-- @
422-- @
423+--
424+-- In this implementation each field's value gets decoded using `parseQueryParam`.
425+-- Two field types are exceptions:
426+--
427+-- - for values of type @'Maybe' a@ an entry is parsed if present in the 'Form'
428+-- and the is decoded with 'parseQueryParam'; if no entry is present result is 'Nothing';
429+--
430+-- - for values of type @[a]@ (except @['Char']@) all entries are parsed to produce a list of parsed values;
431+--
432+-- Here's an example:
433+--
434+-- @
435+-- data Post = Post
436+-- { title :: String
437+-- , subtitle :: Maybe String
438+-- , comments :: [String]
439+-- } deriving ('Generic', 'Show')
440+--
441+-- instance 'FromForm' Post
442+-- @
443+--
444+-- >>> urlDecodeAsForm "comments=Nice%20post%21&comments=%2B1&title=Test" :: Either Text Post
445+-- Right (Post {title = "Test", subtitle = Nothing, comments = ["Nice post!","+1"]})
396genericFromForm :: forall a. (Generic a, GFromForm a (Rep a)) => FormOptions -> Form -> Either Text a
446genericFromForm :: forall a. (Generic a, GFromForm a (Rep a)) => FormOptions -> Form -> Either Text a
397genericFromForm opts f = to <$> gFromForm (Proxy :: Proxy a) opts f
447genericFromForm opts f = to <$> gFromForm (Proxy :: Proxy a) opts f
398
448