Usage samples with commentsΒΆ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | {-# LANGUAGE OverloadedStrings #-}
module Main where
import Data.Text
import Text.Digestive
import Text.Digestive.Aeson
import Data.Scientific
import Data.Aeson hiding ((.:))
-- A json 'Value' can be validated using the `digestJSON` function.
--
-- digestJSON :: Monad m => Form v m a -> Value -> m (View v, Maybe a)
--
-- The first argument is most important data type here, which is
--
-- type Form v m a = FormTree m v m a
--
-- The three type parameters are:
--
-- v: the type for error message. Usually Text or String
-- m: the monad in which validators operate. For starters, this can be IO
-- a: The data type that we want the json to be converted to
-- Api summary.
-- Digestive functor library provides functions to create the Form values
-- for String, Text and Instance of Show/Read.
--
-- Once you have a Form, you can
-- use the .: function to read the corresponding typed from a json key. For ex
-- If you have a form that can read an Integer, you can make a form that will
-- read an integer from the "age" filed using
-- "age" .: formInt
-- Once you have a form that reads the value of type a, you can add validation check
-- to the form using the "check" function. This function accepts a Form of type `a`
-- and function `a -> Bool` and a validation message and returns another Form of
-- the same type, but with validation added.
-- Then you apply the Forms thus created to Aeson values using the digestJSON function
-- to obtain the successfully parsed and validated value, along with a "View' that
-- contains validation messages.
-- Those are the basics and let us see some examples.
-- Note: We will be validating types of 'Value' which is a data type exported by the Aeson json parsing libray.
-- here are a couple of functions that will create values of type Value.
stringValue :: Value
stringValue = stringValue'
where
Just stringValue' = decode "\"A string\""
-- here is a Value that represents a string in an object
wrappedStringValue :: Value
wrappedStringValue = stringValue'
where
Just stringValue' = decode "{\"InputString\": \"A string\"}"
-- Here we create a form that can read (but not validate) a String.
-- We use the `string` function from digestive functors library.
-- The Maybe argument is a default value to return, incase the validation fails.
stringForm :: Form Text IO String
stringForm = string Nothing
-- Here is a form for reading a String that do one validation
stringFormWithValidation :: Form Text IO String
stringFormWithValidation = check "String need to be at least 10 chars long" testLength $ string Nothing
where
testLength :: String -> Bool
testLength s = Prelude.length s >= 10
-- Here is a form that reads a string from a key "InputString" from a json Object
-- {"InputString" : "A String"}
stringFormValidationFromKey :: Form Text IO String
stringFormValidationFromKey = "InputString" .: stringForm
-- Here is a form that reads a user defined datatype from the same json as above
data UserName = UserName String
stringFormValidationFromKeyToUserDefined :: Form Text IO UserName
stringFormValidationFromKeyToUserDefined = UserName <$> "InputString" .: stringForm
-- PARSING INTEGERS AND SUCH
-- Here is a form that read an integer that is embedded as a String in the json.
-- For ex: {"age" : "25"}
numberFromStringForm :: Form Text IO Int
numberFromStringForm = "age" .: stringRead "Failed to parse as a number" Nothing
--
-- Please note in the above that the number 25 is wrapped in quotes.
-- If you want to read from unwrapped numeric values.
-- For ex: {"age" : 25}, You have to first create
-- a form that can read a Scientific value, and then use the functor instance to
-- make forms for other number types from it. Here is how you would read an unwrapped integer
numberFromNumberForm :: Form Text IO Int
numberFromNumberForm = floor <$> scientificForm
where
scientificForm :: Form Text IO Scientific
scientificForm = "age" .: stringRead "Failed to parse as a number" Nothing
testStringForm :: IO ()
testStringForm = do
validationResult <- digestJSON stringForm stringValue
putStrLn $ show validationResult
validationResult <- digestJSON stringFormWithValidation stringValue
putStrLn $ show validationResult
validationResult <- digestJSON stringFormValidationFromKey wrappedStringValue
putStrLn $ show validationResult
main = return ()
|