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 "{ \"userName\": \"Ada\", \"userAge\": 36 }" update view
where
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" <> 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
Coming soon — an aeson polyfill 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 — will work with miso unchanged, with no bridge package and no import churn: keep importing Miso.JSON and flip the flag.