Platform
JSON
Miso.JSON is a microaeson-inspired JSON library specialised to MisoString. On the JS / WASM backends it delegates encoding and decoding to the JavaScript runtime (JSON.stringify / JSON.parse) for performance; on the server (ssr) it uses a pure Haskell implementation. It is used internally by Miso.Event.Decoder, Miso.Fetch and Miso.WebSocket.
Value
data Value
= Number Double
| Bool Bool
| String MisoString
| Array [Value]
| Object Object
| NullEncoding and decoding
encode value
-- uses the JS runtime on the client,
-- pure on the server
encodePure value
-- always the pure Haskell implementation
decode s :: Maybe a
eitherDecode s :: Either MisoString aToJSON / FromJSON
Derive instances via GHC.Generics:
{-# LANGUAGE DeriveGeneric #-}
import GHC.Generics
import Miso.JSON
data User = User
{ name :: MisoString
, age :: Int
} deriving (Generic)
instance ToJSON User
instance FromJSON UserUse genericToJSON / genericParseJSON with Options to customise field and constructor names; camelTo2 converts camelCase to snake_case:
instance ToJSON User where
toJSON = genericToJSON defaultOptions
{ fieldLabelModifier = camelTo2 '_' }Building and parsing objects
-- Build
object
[ "name" .= ms "Alice"
, "age" .= (30 :: Int)
]
-- Parse (inside a withObject
-- callback or event decoder)
withObject "User" $ \o -> User
<$> o .: "name"
-- required field
<*> o .: "age"
o .:? "nickname"
-- optional field → Maybe a
o .:! "nickname"
-- optional field, explicit null → Maybe a
p .!= "anon"
-- default for a Maybe parserPretty printing
encodePretty value
-- indented with defConfig (2-space indent)
encodePretty' config value
-- custom ConfigTry it
✓ User {userName = "Ada", userAge = 36}
{"userAge":36,"userName":"Ada"}data User = User
{ userName :: MisoString
, userAge :: Int
} deriving (Show, Eq, Generic, ToJSON, FromJSON)
-- generic instances from Miso.JSON
data JsonAction = Edit MisoString
jsonRoundTrip
:: Component ctx () MisoString JsonAction
jsonRoundTrip = component initial update view
where
initial = "{ \"userName\": \"Ada\", \"userAge\": 36 }"
update (Edit s) = this .= s
view input =
H.div_ []
[ H.textarea_
[ HP.value_ input
, HE.onInput Edit
, textProp "rows" "3"
]
, case eitherDecode input :: Either MisoString User of
Left err ->
H.p_ [ HP.class_ "muted" ] [ "✗ ", text err ]
Right user ->
H.pre_ []
[ "✓ "
, text (ms (show user))
, "\n"
, text (encode user)
]
]miso-aeson
Prefer aeson? The miso-aeson package bridges aeson's ToJSON / FromJSON instances with miso's event decoder and fetch API, so existing instances work without rewriting.
aeson polyfill
An aeson polyfill lives behind an aeson cabal flag (-faeson): building miso with it defines every operator and class exported by Miso.JSON (ToJSON, FromJSON, .:, .=, withObject, encode, decode, …) in terms of Data.Aeson. Existing aeson code — and its instances — works with miso unchanged, with no bridge package and no import churn: keep importing Miso.JSON and flip the flag.