-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Parse and validate forms in JSON format -- -- Parse and validate forms in JSON format. @package forma @version 0.2.0 -- | This module provides a tool for validation of forms that are -- represented in the JSON format. Sending forms in JSON format via an -- AJAX request instead of traditional submitting of forms has a number -- of advantages: -- -- -- -- The task of validation of a form in the JSON format may seem simple, -- but it's not trivial to get it right. The library allows you to: -- -- -- -- This library requires at least GHC 8 to work. -- -- You need to enable at least DataKinds and -- TypeApplications language extensions to use this library. module Web.Forma -- | Construct a parser for a field. Combine multiple fields using -- applicative syntax like so: -- --
--   type LoginFields = '["username", "password", "remember_me"]
--   
--   data LoginForm = LoginForm
--     { loginUsername   :: Text
--     , loginPassword   :: Text
--     , loginRememberMe :: Bool
--     }
--   
--   loginForm :: Monad m => FormParser LoginFields m LoginForm
--   loginForm = LoginForm
--     <$> field @"username" notEmpty
--     <*> field @"password" notEmpty
--     <*> field' @"remember_me"
--   
--   notEmpty :: Monad m => Text -> ExceptT Text m Text
--   notEmpty txt =
--     if T.null txt
--       then throwError "This field cannot be empty"
--       else return txt
--   
-- -- Referring to the types in the function's signature, s is -- extracted from JSON Value for you automatically using its -- FromJSON instance. The field value is taken in assumption that -- top level Value is a dictionary, and field name is a key in -- that dictionary. So for example a valid JSON input for the form shown -- above could be this: -- --
--   {
--     "username": "Bob",
--     "password": "123",
--     "remember_me": true
--   }
--   
-- -- Once value of type s is extracted, validation phase beings. -- The supplied checker (you can easy compose them with -- (>=>), as they are Kleisli arrows) is applied to -- the s value and validation either succeeds producing an -- a value, or we collect an error in the form of a value of -- e type, which is fed into mkFieldError internally. -- -- To run a form composed from fields, see runForm. field :: forall (name :: Symbol) (names :: [Symbol]) m e s a. (KnownSymbol name, InSet name names, Monad m, ToJSON e, FromJSON s) => (s -> ExceptT e m a) -> FormParser names m a -- | The same as field, but does not require a checker. field' :: forall (name :: Symbol) (names :: [Symbol]) m a. (KnownSymbol name, InSet name names, Monad m, FromJSON a) => FormParser names m a -- | Transform a form by applying a checker on its result. -- --
--   passwordsMatch (a, b) = do
--     if a == b
--       then return a
--       else throwError "Passwords don't match!"
--   
--   createNewPasswordForm =
--     withCheck @"password_confirmation" passwordsMatch
--       ((,) <$> field @"password" notEmpty
--            <*> field @"password_confirmation" notEmpty)
--   
-- -- Note that you must specify the field name on which to add a validation -- error message in case the check fails. withCheck :: forall (name :: Symbol) (names :: [Symbol]) m e s a. (KnownSymbol name, InSet name names, Monad m, ToJSON e) => (s -> ExceptT e m a) -> FormParser names m s -> FormParser names m a -- | Run the supplied parser on given input and call the specified callback -- that uses the result of parsing on success. -- -- The callback can either report a FieldError (one or more), or -- report success providing a value that will be converted to JSON and -- included in the resulting Value (response). -- -- The resulting Value has the following format: -- --
--   {
--     "parse_error": "Text or null."
--     "field_errors":
--       {
--         "foo": "Foo's error serialized to JSON.",
--         "bar": "Bar's error…"
--       }
--     "result": "What you return from the callback in FormResultSuccess."
--   }
--   
runForm :: (Monad m, ToJSON b) => FormParser names m a -> Value -> (a -> m (FormResult names b)) -> m Value -- | Pick a name from a given collection of names. -- -- Typical usage: -- --
--   type Fields = '["foo", "bar", "baz"]
--   
--   myName :: SelectedName Fields
--   myName = pick @"foo" @Fields
--   
-- -- It's a good idea to use pick to get field names not only where -- this approach is imposed by the library, but everywhere you need to -- use the field names, in your templates for example. pick :: forall (name :: Symbol) (names :: [Symbol]). (KnownSymbol name, InSet name names) => SelectedName names -- | Extract a Text value from SelectedName. unSelectedName :: SelectedName names -> Text -- | This is a smart constructor for the FieldError type, and the -- only way to obtain values of that type. -- -- Typical usage: -- --
--   type Fields = '["foo", "bar", "baz"]
--   
--   myError :: FieldError Fields
--   myError = mkFieldError (pick @"foo" @Fields) "That's all wrong."
--   
-- -- See also: pick (to create SelectedName). mkFieldError :: ToJSON e => SelectedName names -> e -> FieldError names -- | The type represents the parser that you can run on a Value with -- the help of runForm. The only way for the user of the library -- to create a parser is via the field function. Users can combine -- existing parsers using the applicative notation. -- -- FormParser is parametrized by three type variables: -- -- -- -- FormParser is not a monad because it's not possible to write a -- Monad instance with the properties that we want (validation -- errors should not lead to short-cutting behavior). data FormParser (names :: [Symbol]) m a -- | This a type that user must return in the callback passed to the -- runForm function. Quite simply, it allows you either report a -- error or finish successfully. data FormResult (names :: [Symbol]) a -- | Form submission failed, here are the validation errors. FormResultError :: (FieldError names) -> FormResult a -- | Form submission succeeded, send this info. FormResultSuccess :: a -> FormResult a -- | SelectedName names represents a name (Text -- value) that is guaranteed to be in the names, which is a set -- of strings on type level. The purpose if this type is to avoid typos -- and to force users to update field names everywhere when they decide -- to change them. The only way to obtain a value of type -- SelectedName is via the pick function, which see. data SelectedName (names :: [Symbol]) -- | The type function computes a Constraint which is satisfied when -- its first argument is contained in its second argument. Otherwise a -- friendly type error is displayed. -- | Error info in JSON format associated with a particular form field. -- Parametrized by names, which is a collection of field names -- (on type level) the target field belongs to. FieldError is an -- instance of Semigroup and that's how you combine values of that -- type. Note that it's not a Monoid, because we do not want to -- allow empty FieldErrors. data FieldError (names :: [Symbol]) instance GHC.Base.Functor (Web.Forma.BranchState names) instance GHC.Show.Show a => GHC.Show.Show (Web.Forma.FormResult names a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Web.Forma.FormResult names a) instance GHC.Show.Show (Web.Forma.FieldError names) instance GHC.Classes.Eq (Web.Forma.FieldError names) instance GHC.Show.Show (Web.Forma.SelectedName names) instance GHC.Classes.Eq (Web.Forma.SelectedName names) instance GHC.Base.Applicative (Web.Forma.BranchState names) instance GHC.Base.Functor m => GHC.Base.Functor (Web.Forma.FormParser names m) instance GHC.Base.Applicative m => GHC.Base.Applicative (Web.Forma.FormParser names m) instance GHC.Base.Applicative m => GHC.Base.Alternative (Web.Forma.FormParser names m) instance Data.Semigroup.Semigroup (Web.Forma.FieldError names) instance Data.Aeson.Types.ToJSON.ToJSON (Web.Forma.FieldError names) instance Data.Default.Class.Default (Web.Forma.Response names) instance Data.Aeson.Types.ToJSON.ToJSON (Web.Forma.Response names)