Skip to content

Instantly share code, notes, and snippets.

@pwm
Created February 9, 2020 12:47
Show Gist options
  • Save pwm/6c89322876e8e43927736ddd9c5ce101 to your computer and use it in GitHub Desktop.
Save pwm/6c89322876e8e43927736ddd9c5ce101 to your computer and use it in GitHub Desktop.
a Jijo Example
module JijoExample where
import Control.Category ((>>>))
import Data.Aeson
import Data.Aeson.Types
import qualified Data.ByteString.Lazy.Char8 as BSL
import Data.Scientific (Scientific)
import Data.Text (Text)
import qualified Data.Text as Text
import qualified Data.Text.Lazy.Encoding as Text
import qualified Data.Text.Lazy.IO as Text
import GHC.Records (getField)
import Jijo.Definition
import Prelude
--
newtype PosNumber = UnsafeMkPosNumber Scientific
deriving stock (Show, Eq, Ord)
getPosNumber :: PosNumber -> Scientific
getPosNumber (UnsafeMkPosNumber x) = x
mkPosNumber :: Scientific -> Either Text PosNumber
mkPosNumber x
| x > 0 = Right $ UnsafeMkPosNumber x
| otherwise = Left "NonPositiveNumber "
-- composing the (library provided) jNumber with our own validator
jPosNumber :: JDefinition Text Value PosNumber
jPosNumber = jNumber >>> jDefinition jValidate jEncode
where
jValidate t = case mkPosNumber t of
Left e -> jValidationFail e
Right v -> pure v
jEncode = getPosNumber
--
data Person
= MkPerson
{ name :: Text,
age :: PosNumber,
height :: Maybe PosNumber
}
deriving stock (Show, Eq, Ord)
-- using applicative to build up a record validating its fields
jPerson :: JDefinition Text Value Person
jPerson =
defineJObject $
MkPerson
<$> inJField "name" (getField @"name") jString
<*> inJField "age" (getField @"age") jPosNumber
<*> inOptJField "height" (getField @"height") jPosNumber
instance FromJSON Person where
parseJSON = (parseJSON_viaDefinition . mapJError Text.unpack) jPerson
instance ToJSON Person where
toJSON = toJSON_viaDefinition jPerson
--
run :: IO ()
run = do
j <- Text.encodeUtf8 <$> Text.getLine
case eitherDecode j >>= parseEither (parseJSON @Person) of
Left e -> putStrLn e
Right v -> print v >> BSL.putStrLn (encode v)
run
--
{-
λ> run
{}
Error in $: $: missing field name
$: missing field age
{"name": null, "age": true}
Error in $: $.age: type not one of {number}
$.name: type not one of {string}
{"name": "foo", "age": -1}
Error in $: $.age: NonPositiveNumber
{"name": "foo", "age": 1}
MkPerson {name = "foo", age = UnsafeMkPosNumber 1.0, height = Nothing}
{"age":1,"name":"foo"}
-}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment